* [PATCH BlueZ 3/4] shared/gatt-client: Remove notification if its attribute is removed
From: Luiz Augusto von Dentz @ 2020-07-16 23:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20200716231857.934396-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
If the attribute is being removed from the database it means the
notification shall also be dropped, that way users don't have to
cleanup its subscriptions themselves.
---
src/shared/gatt-client.c | 70 +++++++++++++++++++++++++++++-----------
1 file changed, 52 insertions(+), 18 deletions(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index 0b81a7a5c..e21aca1f0 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -174,9 +174,12 @@ static void request_unref(void *data)
}
struct notify_chrc {
+ struct bt_gatt_client *client;
+ struct gatt_db_attribute *attr;
uint16_t value_handle;
uint16_t ccc_handle;
uint16_t properties;
+ unsigned int notify_id;
int notify_count; /* Reference count of registered notify callbacks */
/* Pending calls to register_notify are queued here so that they can be
@@ -235,6 +238,51 @@ static void find_ccc(struct gatt_db_attribute *attr, void *user_data)
*ccc_ptr = attr;
}
+static bool match_notify_chrc(const void *data, const void *user_data)
+{
+ const struct notify_data *notify_data = data;
+ const struct notify_chrc *chrc = user_data;
+
+ return notify_data->chrc == chrc;
+}
+
+static void notify_data_cleanup(void *data)
+{
+ struct notify_data *notify_data = data;
+
+ if (notify_data->att_id)
+ bt_att_cancel(notify_data->client->att, notify_data->att_id);
+
+ notify_data_unref(notify_data);
+}
+
+static void notify_chrc_free(void *data)
+{
+ struct notify_chrc *chrc = data;
+
+ if (chrc->notify_id)
+ gatt_db_attribute_unregister(chrc->attr, chrc->notify_id);
+
+ queue_destroy(chrc->reg_notify_queue, notify_data_unref);
+ free(chrc);
+}
+
+static void chrc_removed(struct gatt_db_attribute *attr, void *user_data)
+{
+ struct notify_chrc *chrc = user_data;
+ struct bt_gatt_client *client = chrc->client;
+ struct notify_data *data;
+
+ chrc->notify_id = 0;
+
+ while ((data = queue_remove_if(client->notify_list, match_notify_chrc,
+ chrc)))
+ notify_data_cleanup(data);
+
+ queue_remove(client->notify_chrcs, chrc);
+ notify_chrc_free(chrc);
+}
+
static struct notify_chrc *notify_chrc_create(struct bt_gatt_client *client,
uint16_t value_handle)
{
@@ -274,22 +322,18 @@ static struct notify_chrc *notify_chrc_create(struct bt_gatt_client *client,
if (ccc)
chrc->ccc_handle = gatt_db_attribute_get_handle(ccc);
+ chrc->client = client;
+ chrc->attr = attr;
chrc->value_handle = value_handle;
chrc->properties = properties;
+ chrc->notify_id = gatt_db_attribute_register(attr, chrc_removed, chrc,
+ NULL);
queue_push_tail(client->notify_chrcs, chrc);
return chrc;
}
-static void notify_chrc_free(void *data)
-{
- struct notify_chrc *chrc = data;
-
- queue_destroy(chrc->reg_notify_queue, notify_data_unref);
- free(chrc);
-}
-
static bool match_notify_data_id(const void *a, const void *b)
{
const struct notify_data *notify_data = a;
@@ -303,16 +347,6 @@ struct handle_range {
uint16_t end;
};
-static void notify_data_cleanup(void *data)
-{
- struct notify_data *notify_data = data;
-
- if (notify_data->att_id)
- bt_att_cancel(notify_data->client->att, notify_data->att_id);
-
- notify_data_unref(notify_data);
-}
-
struct discovery_op;
typedef void (*discovery_op_complete_func_t)(struct discovery_op *op,
--
2.25.3
^ permalink raw reply related
* [PATCH BlueZ 1/4] shared/att: Fix possible crash on disconnect
From: Luiz Augusto von Dentz @ 2020-07-16 23:18 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
If there are pending request while disconnecting they would be notified
but clients may endup being freed in the proccess which will then be
calling bt_att_cancel to cancal its requests causing the following
trace:
Invalid read of size 4
at 0x1D894C: enable_ccc_callback (gatt-client.c:1627)
by 0x1D247B: disc_att_send_op (att.c:417)
by 0x1CCC17: queue_remove_all (queue.c:354)
by 0x1D47B7: disconnect_cb (att.c:635)
by 0x1E0707: watch_callback (io-glib.c:170)
by 0x48E963B: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.6400.4)
by 0x48E9AC7: ??? (in /usr/lib/libglib-2.0.so.0.6400.4)
by 0x48E9ECF: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.6400.4)
by 0x1E0E97: mainloop_run (mainloop-glib.c:79)
by 0x1E13B3: mainloop_run_with_signal (mainloop-notify.c:201)
by 0x12BC3B: main (main.c:770)
Address 0x7d40a28 is 24 bytes inside a block of size 32 free'd
at 0x484A2E0: free (vg_replace_malloc.c:540)
by 0x1CCC17: queue_remove_all (queue.c:354)
by 0x1CCC83: queue_destroy (queue.c:73)
by 0x1D7DD7: bt_gatt_client_free (gatt-client.c:2209)
by 0x16497B: batt_free (battery.c:77)
by 0x16497B: batt_remove (battery.c:286)
by 0x1A0013: service_remove (service.c:176)
by 0x1A9B7B: device_remove_gatt_service (device.c:3691)
by 0x1A9B7B: gatt_service_removed (device.c:3805)
by 0x1CC90B: queue_foreach (queue.c:220)
by 0x1DE27B: notify_service_changed.isra.0.part.0 (gatt-db.c:369)
by 0x1DE387: notify_service_changed (gatt-db.c:361)
by 0x1DE387: gatt_db_service_destroy (gatt-db.c:385)
by 0x1DE3EF: gatt_db_remove_service (gatt-db.c:519)
by 0x1D674F: discovery_op_complete (gatt-client.c:388)
by 0x1D6877: discover_primary_cb (gatt-client.c:1260)
by 0x1E220B: discovery_op_complete (gatt-helpers.c:628)
by 0x1E249B: read_by_grp_type_cb (gatt-helpers.c:730)
by 0x1D247B: disc_att_send_op (att.c:417)
by 0x1CCC17: queue_remove_all (queue.c:354)
by 0x1D47B7: disconnect_cb (att.c:635)
---
src/shared/att.c | 46 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 40 insertions(+), 6 deletions(-)
diff --git a/src/shared/att.c b/src/shared/att.c
index ed3af2920..58f23dfcb 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -84,6 +84,7 @@ struct bt_att {
struct queue *req_queue; /* Queued ATT protocol requests */
struct queue *ind_queue; /* Queued ATT protocol indications */
struct queue *write_queue; /* Queue of PDUs ready to send */
+ bool in_disc; /* Cleanup queues on disconnect_cb */
bt_att_timeout_func_t timeout_callback;
bt_att_destroy_func_t timeout_destroy;
@@ -222,8 +223,10 @@ static void destroy_att_send_op(void *data)
free(op);
}
-static void cancel_att_send_op(struct att_send_op *op)
+static void cancel_att_send_op(void *data)
{
+ struct att_send_op *op = data;
+
if (op->destroy)
op->destroy(op->user_data);
@@ -631,11 +634,6 @@ static bool disconnect_cb(struct io *io, void *user_data)
/* Dettach channel */
queue_remove(att->chans, chan);
- /* Notify request callbacks */
- queue_remove_all(att->req_queue, NULL, NULL, disc_att_send_op);
- queue_remove_all(att->ind_queue, NULL, NULL, disc_att_send_op);
- queue_remove_all(att->write_queue, NULL, NULL, disc_att_send_op);
-
if (chan->pending_req) {
disc_att_send_op(chan->pending_req);
chan->pending_req = NULL;
@@ -654,6 +652,15 @@ static bool disconnect_cb(struct io *io, void *user_data)
bt_att_ref(att);
+ att->in_disc = true;
+
+ /* Notify request callbacks */
+ queue_remove_all(att->req_queue, NULL, NULL, disc_att_send_op);
+ queue_remove_all(att->ind_queue, NULL, NULL, disc_att_send_op);
+ queue_remove_all(att->write_queue, NULL, NULL, disc_att_send_op);
+
+ att->in_disc = false;
+
queue_foreach(att->disconn_list, disconn_handler, INT_TO_PTR(err));
bt_att_unregister_all(att);
@@ -1574,6 +1581,30 @@ bool bt_att_chan_cancel(struct bt_att_chan *chan, unsigned int id)
return true;
}
+static bool bt_att_disc_cancel(struct bt_att *att, unsigned int id)
+{
+ struct att_send_op *op;
+
+ op = queue_find(att->req_queue, match_op_id, UINT_TO_PTR(id));
+ if (op)
+ goto done;
+
+ op = queue_find(att->ind_queue, match_op_id, UINT_TO_PTR(id));
+ if (op)
+ goto done;
+
+ op = queue_find(att->write_queue, match_op_id, UINT_TO_PTR(id));
+
+done:
+ if (!op)
+ return false;
+
+ /* Just cancel since disconnect_cb will be cleaning up */
+ cancel_att_send_op(op);
+
+ return true;
+}
+
bool bt_att_cancel(struct bt_att *att, unsigned int id)
{
const struct queue_entry *entry;
@@ -1591,6 +1622,9 @@ bool bt_att_cancel(struct bt_att *att, unsigned int id)
return true;
}
+ if (att->in_disc)
+ return bt_att_disc_cancel(att, id);
+
op = queue_remove_if(att->req_queue, match_op_id, UINT_TO_PTR(id));
if (op)
goto done;
--
2.25.3
^ permalink raw reply related
* [PATCH BlueZ 2/4] shared/gatt-db: Add support for notifying attribute changes
From: Luiz Augusto von Dentz @ 2020-07-16 23:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20200716231857.934396-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This enables to get notified when an attribute has been changed e.g.
it is being removed so the code can detect changes changes at attribute
level.
---
src/shared/gatt-db.c | 103 +++++++++++++++++++++++++++++++++++++++++++
src/shared/gatt-db.h | 8 ++++
2 files changed, 111 insertions(+)
diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
index 5eccab3b9..e939ddc3a 100644
--- a/src/shared/gatt-db.c
+++ b/src/shared/gatt-db.c
@@ -81,6 +81,13 @@ struct notify {
void *user_data;
};
+struct attribute_notify {
+ unsigned int id;
+ gatt_db_attribute_cb_t removed;
+ gatt_db_destroy_func_t destroy;
+ void *user_data;
+};
+
struct pending_read {
struct gatt_db_attribute *attrib;
unsigned int id;
@@ -114,6 +121,9 @@ struct gatt_db_attribute {
unsigned int write_id;
struct queue *pending_writes;
+
+ unsigned int next_notify_id;
+ struct queue *notify_list;
};
struct gatt_db_service {
@@ -171,6 +181,16 @@ static void pending_write_free(void *data)
pending_write_result(p, -ECANCELED);
}
+static void attribute_notify_destroy(void *data)
+{
+ struct attribute_notify *notify = data;
+
+ if (notify->destroy)
+ notify->destroy(notify->user_data);
+
+ free(notify);
+}
+
static void attribute_destroy(struct gatt_db_attribute *attribute)
{
/* Attribute was not initialized by user */
@@ -179,6 +199,7 @@ static void attribute_destroy(struct gatt_db_attribute *attribute)
queue_destroy(attribute->pending_reads, pending_read_free);
queue_destroy(attribute->pending_writes, pending_write_free);
+ queue_destroy(attribute->notify_list, attribute_notify_destroy);
free(attribute->value);
free(attribute);
@@ -208,6 +229,7 @@ static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service,
attribute->pending_reads = queue_new();
attribute->pending_writes = queue_new();
+ attribute->notify_list = queue_new();
return attribute;
@@ -352,12 +374,38 @@ static bool db_hash_update(void *user_data)
return false;
}
+static void handle_attribute_notify(void *data, void *user_data)
+{
+ struct attribute_notify *notify = data;
+ struct gatt_db_attribute *attrib = user_data;
+
+ if (notify->removed)
+ notify->removed(attrib, notify->user_data);
+}
+
+static void notify_attribute_changed(struct gatt_db_service *service)
+{
+ int i;
+
+ for (i = 0; i < service->num_handles; i++) {
+ struct gatt_db_attribute *attr = service->attributes[i];
+
+ if (!attr)
+ continue;
+
+ queue_foreach(attr->notify_list, handle_attribute_notify, attr);
+ }
+}
+
static void notify_service_changed(struct gatt_db *db,
struct gatt_db_service *service,
bool added)
{
struct notify_data data;
+ if (!added)
+ notify_attribute_changed(service);
+
if (queue_isempty(db->notify_list))
return;
@@ -1993,3 +2041,58 @@ void *gatt_db_attribute_get_user_data(struct gatt_db_attribute *attrib)
return attrib->user_data;
}
+
+static bool match_attribute_notify_id(const void *a, const void *b)
+{
+ const struct attribute_notify *notify = a;
+ unsigned int id = PTR_TO_UINT(b);
+
+ return notify->id == id;
+}
+
+unsigned int gatt_db_attribute_register(struct gatt_db_attribute *attrib,
+ gatt_db_attribute_cb_t removed,
+ void *user_data,
+ gatt_db_destroy_func_t destroy)
+{
+ struct attribute_notify *notify;
+
+ if (!attrib || !removed)
+ return 0;
+
+ notify = new0(struct attribute_notify, 1);
+ notify->removed = removed;
+ notify->destroy = destroy;
+ notify->user_data = user_data;
+
+ if (attrib->next_notify_id < 1)
+ attrib->next_notify_id = 1;
+
+ notify->id = attrib->next_notify_id++;
+
+ if (!queue_push_tail(attrib->notify_list, notify)) {
+ free(notify);
+ return 0;
+ }
+
+ return notify->id;
+}
+
+bool gatt_db_attribute_unregister(struct gatt_db_attribute *attrib,
+ unsigned int id)
+{
+ struct attribute_notify *notify;
+
+ if (!attrib || !id)
+ return false;
+
+ notify = queue_find(attrib->notify_list, match_attribute_notify_id,
+ UINT_TO_PTR(id));
+ if (!notify)
+ return false;
+
+ queue_remove(attrib->notify_list, notify);
+ attribute_notify_destroy(notify);
+
+ return true;
+}
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index a0fd66c53..5bf19d302 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -281,3 +281,11 @@ bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib,
bool gatt_db_attribute_reset(struct gatt_db_attribute *attrib);
void *gatt_db_attribute_get_user_data(struct gatt_db_attribute *attrib);
+
+unsigned int gatt_db_attribute_register(struct gatt_db_attribute *attrib,
+ gatt_db_attribute_cb_t removed,
+ void *user_data,
+ gatt_db_destroy_func_t destroy);
+
+bool gatt_db_attribute_unregister(struct gatt_db_attribute *attrib,
+ unsigned int id);
--
2.25.3
^ permalink raw reply related
* [PATCH BlueZ 4/4] share/gatt-client: Don't remove active services
From: Luiz Augusto von Dentz @ 2020-07-16 23:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20200716231857.934396-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Only remove services that have not been fetched completed as
unsuccessful discovery may be the result of an aborted connection the
attributes that have been fetched previously are likely to be valid.
---
src/shared/gatt-client.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index e21aca1f0..5ba8e83ba 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -407,11 +407,17 @@ static void discovery_op_complete(struct discovery_op *op, bool success,
gatt_db_unregister(op->client->db, op->db_id);
op->db_id = 0;
- /* Remove services pending */
+ /* Remove staled services */
for (svc = queue_get_entries(op->pending_svcs); svc; svc = svc->next) {
struct gatt_db_attribute *attr = svc->data;
uint16_t start, end;
+ /* Don't remove services that already been marked as active
+ * previously.
+ */
+ if (gatt_db_service_get_active(attr))
+ continue;
+
gatt_db_attribute_get_service_data(attr, &start, &end,
NULL, NULL);
--
2.25.3
^ permalink raw reply related
* Re: [RFC PATCH net-next 6/6] ice: implement devlink parameters to control flash update
From: Jakub Kicinski @ 2020-07-16 22:18 UTC (permalink / raw)
To: Jacob Keller, Tom Herbert; +Cc: netdev, Jiri Pirko, Jesse Brandeburg
In-Reply-To: <2ce3eb56-69e3-91fe-96a2-e5e538846e9f@intel.com>
On Thu, 16 Jul 2020 14:52:15 -0700 Jacob Keller wrote:
> On 7/16/2020 2:42 PM, Jakub Kicinski wrote:
> > On Thu, 16 Jul 2020 14:29:40 -0700 Jacob Keller wrote:
> >> On 7/15/2020 5:21 PM, Jacob Keller wrote:
> >>> Ok, that seems reasonable. Ofcourse we'll need to find something generic
> >>> enough that it can be re-used and isn't driver specific.
> >>
> >> Hi Jakub,
> >>
> >> I think I have something that will be more clear and will be sending a
> >> new RFC with the change this afternoon:
> >>
> >> an extension to the DEVLINK_CMD_FLASH_UPDATE with a new parameter,
> >> "overwrite" with these values:
> >>
> >> a) "nothing" (or maybe, "firmware-only" or "binary-only"?, need a way to
> >> clarify difference between settings/vital data and firmware program
> >> binary) will request that we do not overwrite any settings or fields.
> >> This is equivalent to the "PRESERVE_ALL" I had in the original proposal,
> >> where we will maintain all settings and all vital data, but update the
> >> firmware binary.
> >>
> >> b) "settings" will request that the firmware overwrite all the settings
> >> fields with the contents from the new image. However, vital data such as
> >> the PCI Serial ID, VPD section, MAC Addresses, and similar "static" data
> >> will be kept (not overwritten). This is the same as the
> >> "PRESERVE_LIMITED" option I had in the original proposal
> >>
> >> c) "all" or "everything" will request that firmware overwrite all
> >> contents of the image. This means all settings and all vital data will
> >> be overwritten by the contents in the new image.
> >
> > Sorry but I'm still not 100% sure of what the use for this option is
> > beyond an OEM. Is it possible to reset the VPD, board serial, MAC
> > address etc. while flashing a FW image downloaded from a support site?
> > Would that mean that if I flash a rack with one FW image all NICs will
> > start reporting the same serial numbers and use the same MACs?
>
> I think the intent here is for OEMs which would generate/customize the
> images, though I've also been told it may be useful to get a card out of
> some situation where firmware preservation was broken.. (No, I don't
> really have more details on what specifically the situation might be).
> Obviously in most update cases I don't think we expect this to be used.
What I'm getting at is that this seems to inherently require a special
FW image which will carry unique IDs, custom-selected for a particular
board. So I was hoping we can infer the setting from the image being
flashed. But perhaps that's risky.
Let's make sure the description of the option captures the fact that
this is mostly useful in manufacturing and otherwise very rarely needed.
> >> d) if we need it, a "default" that would be the current behavior of
> >> doing whatever the driver default is? (since it's not clear to me what
> >> other implementations do but perhaps they all behavior as either
> >> "nothing" or "all"?
> >
> > As a user I'd expect "nothing" to be the default. Same as your OS
> > update does not wipe out your settings. I think it's also better
> > if the default is decided by Linux, not the drivers.
>
> Right, but I wasn't sure what other drivers/devices implement today and
> didn't want to end up in a "well we don't behave that way so you just
> changed our behavior"..? Hmm. If they all behave this way today then
> it's fine to make "nothing" the default and modify all implementations
> to reject other options.
Understood. Let's make things clear in the submission and CC
maintainers of all drivers which implement devlink flashing today.
Let them complain. If we're too cautious we'll never arrive on sane
defaults.
> >> I think I agree that "factory" settings doesn't really belong here, and
> >> I will try to push for finding an alternative way to allow access to
> >> that behavior. If we wanted it we could use "from_factory" to request
> >> that we overwrite the settings and vital data "from" the factory
> >> portion, but I think that is pushing the boundary here a bit...
> >>
> >> I am aiming to have a new patch up with this proposal
> >
> > Probably best if we understand the use case more clearly, too. Since
> > you have this implemented in your tooling what are the scenarios where
> > factory is expected to be preferred over FW default?
>
> I'll see if I can gather any further information on both this and the
> overwrite-all mode.
>
> My understanding so far is that it is intended as a way to restore the
> device settings/config to what was written in the factory. I agree from
> Linux perspective having this be a separate command (without requiring
> an update) would make the most sense, but that isn't how it was
> implemented today.
>
> The factory settings are stored in a separate section of flash so they
> aren't modified by normal update flows. I am not sure if there is a
> procedure for updating them or if it truly is write-once.
^ permalink raw reply
* Re: [PATCH v4 03/15] mm,madvise: call soft_offline_page() without MF_COUNT_INCREASED
From: Mike Kravetz @ 2020-07-16 23:15 UTC (permalink / raw)
To: Oscar Salvador, akpm
Cc: mhocko, linux-mm, david, aneesh.kumar, naoya.horiguchi,
linux-kernel, Naoya Horiguchi, Oscar Salvador
In-Reply-To: <20200716123810.25292-4-osalvador@suse.de>
On 7/16/20 5:37 AM, Oscar Salvador wrote:
> From: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
>
> The call to get_user_pages_fast is only to get the pointer to a struct
> page of a given address, pinning it is memory-poisoning handler's job,
> so drop the refcount grabbed by get_user_pages_fast
>
> Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
> Signed-off-by: Oscar Salvador <osalvador@suse.com>
Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
--
Mike Kravetz
^ permalink raw reply
* [PATCH v3] panic: prevent panic_timeout * 1000 from overflow
From: Changming Liu @ 2020-07-16 23:15 UTC (permalink / raw)
To: akpm; +Cc: willy, rdunlap, keescook, mcgrof, yzaikin, linux-kernel,
Changming Liu
In-Reply-To: <20200714025058.GZ12769@casper.infradead.org>
Since panic_timeout is an s32 integer passed in through sysctl, the
loop boundary panic_timeout * 1000 could overflow and result in
a zero-delay panic when panic_timeout is greater than INT_MAX/1000.
Fix this by elevating the precision of the loop boundary via
assigning the result to a u64 integer, also in case the loop
counter i might never be greater than u64 timeout = panic_timeout*1000,
elevate its precision to u64(timer) as well. The same applies to
timer_next replacing i_next which is initialized to 0.
Signed-off-by: Changming Liu <charley.ashbringer@gmail.com>
---
Changes in v3:
- change the loop in panic, instead of change the sysctl
- avoid using 64-bit division, doing 64-bit mult instead
kernel/panic.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/kernel/panic.c b/kernel/panic.c
index e2157ca..ef6cd57 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -313,13 +313,16 @@ void panic(const char *fmt, ...)
* Delay timeout seconds before rebooting the machine.
* We can't use the "normal" timers since we just panicked.
*/
+ u64 timeout = panic_timeout * 1000ULL; /* avoid overflow */
+ u64 timer, timer_next = 0;
+
pr_emerg("Rebooting in %d seconds..\n", panic_timeout);
- for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) {
+ for (timer = 0; timer < timeout; timer += PANIC_TIMER_STEP) {
touch_nmi_watchdog();
- if (i >= i_next) {
- i += panic_blink(state ^= 1);
- i_next = i + 3600 / PANIC_BLINK_SPD;
+ if (timer >= timer_next) {
+ timer += panic_blink(state ^= 1);
+ timer_next = timer + 3600 / PANIC_BLINK_SPD;
}
mdelay(PANIC_TIMER_STEP);
}
--
2.7.4
^ permalink raw reply related
* [PATCH v8 5/5] remoteproc: Add coredump debugfs entry
From: Rishabh Bhatnagar @ 2020-07-16 22:20 UTC (permalink / raw)
To: linux-remoteproc, linux-kernel
Cc: bjorn.andersson, mathieu.poirier, sibis, tsoni, psodagud, sidgup,
Rishabh Bhatnagar
In-Reply-To: <1594938035-7327-1-git-send-email-rishabhb@codeaurora.org>
Add coredump debugfs entry to configure the type of dump that will
be collected during recovery. User can select between default or
inline coredump functionality. Also coredump collection can be
disabled through this interface.
This functionality can be configured differently for different
remote processors.
Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Tested-by: Sibi Sankar <sibis@codeaurora.org>
Reviewed-by: Sibi Sankar <sibis@codeaurora.org>
---
drivers/remoteproc/remoteproc_debugfs.c | 90 +++++++++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index 732770e..2e3b3e2 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -28,6 +28,94 @@
static struct dentry *rproc_dbg;
/*
+ * A coredump-configuration-to-string lookup table, for exposing a
+ * human readable configuration via debugfs. Always keep in sync with
+ * enum rproc_coredump_mechanism
+ */
+static const char * const rproc_coredump_str[] = {
+ [RPROC_COREDUMP_DEFAULT] = "default",
+ [RPROC_COREDUMP_INLINE] = "inline",
+ [RPROC_COREDUMP_DISABLED] = "disabled",
+};
+
+/* Expose the current coredump configuration via debugfs */
+static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct rproc *rproc = filp->private_data;
+ char buf[20];
+ int len;
+
+ len = scnprintf(buf, sizeof(buf), "%s\n",
+ rproc_coredump_str[rproc->dump_conf]);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+/*
+ * By writing to the 'coredump' debugfs entry, we control the behavior of the
+ * coredump mechanism dynamically. The default value of this entry is "default".
+ *
+ * The 'coredump' debugfs entry supports these commands:
+ *
+ * default: This is the default coredump mechanism. When the remoteproc
+ * crashes the entire coredump will be copied to a separate buffer
+ * and exposed to userspace.
+ *
+ * inline: The coredump will not be copied to a separate buffer and the
+ * recovery process will have to wait until data is read by
+ * userspace. But this avoid usage of extra memory.
+ *
+ * disabled: This will disable coredump. Recovery will proceed without
+ * collecting any dump.
+ */
+static ssize_t rproc_coredump_write(struct file *filp,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct rproc *rproc = filp->private_data;
+ int ret, err = 0;
+ char buf[20];
+
+ if (count > sizeof(buf))
+ return -EINVAL;
+
+ ret = copy_from_user(buf, user_buf, count);
+ if (ret)
+ return -EFAULT;
+
+ /* remove end of line */
+ if (buf[count - 1] == '\n')
+ buf[count - 1] = '\0';
+
+ if (rproc->state == RPROC_CRASHED) {
+ dev_err(&rproc->dev, "can't change coredump configuration\n");
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (!strncmp(buf, "disable", count)) {
+ rproc->dump_conf = RPROC_COREDUMP_DISABLED;
+ } else if (!strncmp(buf, "inline", count)) {
+ rproc->dump_conf = RPROC_COREDUMP_INLINE;
+ } else if (!strncmp(buf, "default", count)) {
+ rproc->dump_conf = RPROC_COREDUMP_DEFAULT;
+ } else {
+ dev_err(&rproc->dev, "Invalid coredump configuration\n");
+ err = -EINVAL;
+ }
+out:
+ return err ? err : count;
+}
+
+static const struct file_operations rproc_coredump_fops = {
+ .read = rproc_coredump_read,
+ .write = rproc_coredump_write,
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+};
+
+/*
* Some remote processors may support dumping trace logs into a shared
* memory buffer. We expose this trace buffer using debugfs, so users
* can easily tell what's going on remotely.
@@ -337,6 +425,8 @@ void rproc_create_debug_dir(struct rproc *rproc)
rproc, &rproc_rsc_table_fops);
debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir,
rproc, &rproc_carveouts_fops);
+ debugfs_create_file("coredump", 0600, rproc->dbg_dir,
+ rproc, &rproc_coredump_fops);
}
void __init rproc_init_debugfs(void)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* Re: Regression: squashfs issues since change "squashfs: migrate from ll_rw_block usage to BIO"
From: Andrew Morton @ 2020-07-16 23:07 UTC (permalink / raw)
To: Bernd Amend; +Cc: phillip, linux-kernel, Stefan Rommel
In-Reply-To: <CAF31+H5ZB7zn73obrc5svLzgfsTnyYe5TKvr7-6atUOqrRY+2w@mail.gmail.com>
On Tue, 14 Jul 2020 21:41:07 +0200 Bernd Amend <bernd.amend@gmail.com> wrote:
> Hi,
>
> With the Linux Kernel version 5.8-rc5/master I am unable to mount some
> squashfs filesystems compressed with "-comp lz4".
> If I try to mount them I get the following error:
> [ 1.084246] SQUASHFS error: lz4 decompression failed, data probably corrupt
> [ 1.084545] SQUASHFS error: Failed to read block 0x873e1001: -5
> [ 1.084761] SQUASHFS error: Unable to read metadata cache entry [873e0fff]
> [ 1.084983] SQUASHFS error: Unable to read directory block [873e0fff:1586]
> [ 1.122564] SQUASHFS error: Unable to read metadata cache entry [873e0fff]
> [ 1.122708] SQUASHFS error: Unable to read directory block [873e0fff:1586]
> [ 1.122862] Starting init: /sbin/init exists but couldn't execute
> it (error -5)
> [ 1.123027] SQUASHFS error: Unable to read metadata cache entry [873e0fff]
> [ 1.123152] SQUASHFS error: Unable to read directory block [873e0fff:1586]
> [ 1.123279] Starting init: /etc/init exists but couldn't execute it
> (error -5)
> [ 1.123444] SQUASHFS error: Unable to read metadata cache entry [873e0fff]
> [ 1.123573] SQUASHFS error: Unable to read directory block [873e0fff:1586]
> [ 1.123713] Starting init: /bin/init exists but couldn't execute it
> (error -5)
> [ 1.123900] SQUASHFS error: Unable to read metadata cache entry [873e0fff]
>
> or
>
> [ 4960.910693] attempt to access beyond end of device
> [ 4960.910695] loop0: rw=2048, want=46, limit=40
> [ 4960.910696] SQUASHFS error: Failed to read block 0x4001: -5
> [ 4960.910697] SQUASHFS error: Unable to read metadata cache entry [3fff]
> [ 4960.910698] SQUASHFS error: Unable to read inode 0x20c5000c
>
> I bisected the issue to the commit "squashfs: migrate from ll_rw_block
> usage to BIO"
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/fs/squashfs?id=93e72b3c612adcaca13d874fcc86c53e6c8da541
>
> The issue can be reproduced by downloading
> https://theworldsend.eu/demo.squashfs (20K) and the following command
> line.
> # mount demo.squashfs mnt && ls mnt && umount mnt
>
> The same squashfs can be mounted using Linux <=5.7.8.
> The kernel config is identical to the Arch Linux Kernel configuration,
> build using gcc 9 and 10 on x86_64.
Thanks. I queued a reversion patch. I'll go ahead with this if we are
unable to get this fixed in the next week or so.
Are you able to check that the below fixes things up?
Thanks.
From: Andrew Morton <akpm@linux-foundation.org>
Subject: revert "squashfs: migrate from ll_rw_block usage to BIO"
Revert 93e72b3c612adc ("squashfs: migrate from ll_rw_block usage to BIO")
due to a regression reported by Bernd Amend.
Link: http://lkml.kernel.org/r/CAF31+H5ZB7zn73obrc5svLzgfsTnyYe5TKvr7-6atUOqrRY+2w@mail.gmail.com
Reported-by: Bernd Amend <bernd.amend@gmail.com>
Cc: Philippe Liard <pliard@google.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Adrien Schildknecht <adrien+dev@schischi.me>
Cc: Phillip Lougher <phillip@squashfs.org.uk>
Cc: Guenter Roeck <groeck@chromium.org>
Cc: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/squashfs/block.c | 273 ++++++++++------------
fs/squashfs/decompressor.h | 5
fs/squashfs/decompressor_multi.c | 9
fs/squashfs/decompressor_multi_percpu.c | 6
fs/squashfs/decompressor_single.c | 9
fs/squashfs/lz4_wrapper.c | 17 -
fs/squashfs/lzo_wrapper.c | 17 -
fs/squashfs/squashfs.h | 4
fs/squashfs/xz_wrapper.c | 51 +---
fs/squashfs/zlib_wrapper.c | 63 ++---
fs/squashfs/zstd_wrapper.c | 62 ++--
11 files changed, 237 insertions(+), 279 deletions(-)
--- a/fs/squashfs/block.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/block.c
@@ -13,7 +13,6 @@
* datablocks and metadata blocks.
*/
-#include <linux/blkdev.h>
#include <linux/fs.h>
#include <linux/vfs.h>
#include <linux/slab.h>
@@ -28,104 +27,45 @@
#include "page_actor.h"
/*
- * Returns the amount of bytes copied to the page actor.
+ * Read the metadata block length, this is stored in the first two
+ * bytes of the metadata block.
*/
-static int copy_bio_to_actor(struct bio *bio,
- struct squashfs_page_actor *actor,
- int offset, int req_length)
-{
- void *actor_addr = squashfs_first_page(actor);
- struct bvec_iter_all iter_all = {};
- struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
- int copied_bytes = 0;
- int actor_offset = 0;
-
- if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all)))
- return 0;
-
- while (copied_bytes < req_length) {
- int bytes_to_copy = min_t(int, bvec->bv_len - offset,
- PAGE_SIZE - actor_offset);
-
- bytes_to_copy = min_t(int, bytes_to_copy,
- req_length - copied_bytes);
- memcpy(actor_addr + actor_offset,
- page_address(bvec->bv_page) + bvec->bv_offset + offset,
- bytes_to_copy);
-
- actor_offset += bytes_to_copy;
- copied_bytes += bytes_to_copy;
- offset += bytes_to_copy;
-
- if (actor_offset >= PAGE_SIZE) {
- actor_addr = squashfs_next_page(actor);
- if (!actor_addr)
- break;
- actor_offset = 0;
- }
- if (offset >= bvec->bv_len) {
- if (!bio_next_segment(bio, &iter_all))
- break;
- offset = 0;
- }
- }
- squashfs_finish_page(actor);
- return copied_bytes;
-}
-
-static int squashfs_bio_read(struct super_block *sb, u64 index, int length,
- struct bio **biop, int *block_offset)
+static struct buffer_head *get_block_length(struct super_block *sb,
+ u64 *cur_index, int *offset, int *length)
{
struct squashfs_sb_info *msblk = sb->s_fs_info;
- const u64 read_start = round_down(index, msblk->devblksize);
- const sector_t block = read_start >> msblk->devblksize_log2;
- const u64 read_end = round_up(index + length, msblk->devblksize);
- const sector_t block_end = read_end >> msblk->devblksize_log2;
- int offset = read_start - round_down(index, PAGE_SIZE);
- int total_len = (block_end - block) << msblk->devblksize_log2;
- const int page_count = DIV_ROUND_UP(total_len + offset, PAGE_SIZE);
- int error, i;
- struct bio *bio;
-
- bio = bio_alloc(GFP_NOIO, page_count);
- if (!bio)
- return -ENOMEM;
+ struct buffer_head *bh;
- bio_set_dev(bio, sb->s_bdev);
- bio->bi_opf = READ;
- bio->bi_iter.bi_sector = block * (msblk->devblksize >> SECTOR_SHIFT);
-
- for (i = 0; i < page_count; ++i) {
- unsigned int len =
- min_t(unsigned int, PAGE_SIZE - offset, total_len);
- struct page *page = alloc_page(GFP_NOIO);
-
- if (!page) {
- error = -ENOMEM;
- goto out_free_bio;
- }
- if (!bio_add_page(bio, page, len, offset)) {
- error = -EIO;
- goto out_free_bio;
+ bh = sb_bread(sb, *cur_index);
+ if (bh == NULL)
+ return NULL;
+
+ if (msblk->devblksize - *offset == 1) {
+ *length = (unsigned char) bh->b_data[*offset];
+ put_bh(bh);
+ bh = sb_bread(sb, ++(*cur_index));
+ if (bh == NULL)
+ return NULL;
+ *length |= (unsigned char) bh->b_data[0] << 8;
+ *offset = 1;
+ } else {
+ *length = (unsigned char) bh->b_data[*offset] |
+ (unsigned char) bh->b_data[*offset + 1] << 8;
+ *offset += 2;
+
+ if (*offset == msblk->devblksize) {
+ put_bh(bh);
+ bh = sb_bread(sb, ++(*cur_index));
+ if (bh == NULL)
+ return NULL;
+ *offset = 0;
}
- offset = 0;
- total_len -= len;
}
- error = submit_bio_wait(bio);
- if (error)
- goto out_free_bio;
-
- *biop = bio;
- *block_offset = index & ((1 << msblk->devblksize_log2) - 1);
- return 0;
-
-out_free_bio:
- bio_free_pages(bio);
- bio_put(bio);
- return error;
+ return bh;
}
+
/*
* Read and decompress a metadata block or datablock. Length is non-zero
* if a datablock is being read (the size is stored elsewhere in the
@@ -136,88 +76,129 @@ out_free_bio:
* algorithms).
*/
int squashfs_read_data(struct super_block *sb, u64 index, int length,
- u64 *next_index, struct squashfs_page_actor *output)
+ u64 *next_index, struct squashfs_page_actor *output)
{
struct squashfs_sb_info *msblk = sb->s_fs_info;
- struct bio *bio = NULL;
- int compressed;
- int res;
- int offset;
+ struct buffer_head **bh;
+ int offset = index & ((1 << msblk->devblksize_log2) - 1);
+ u64 cur_index = index >> msblk->devblksize_log2;
+ int bytes, compressed, b = 0, k = 0, avail, i;
+
+ bh = kcalloc(((output->length + msblk->devblksize - 1)
+ >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL);
+ if (bh == NULL)
+ return -ENOMEM;
if (length) {
/*
* Datablock.
*/
+ bytes = -offset;
compressed = SQUASHFS_COMPRESSED_BLOCK(length);
length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
+ if (next_index)
+ *next_index = index + length;
+
TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
index, compressed ? "" : "un", length, output->length);
+
+ if (length < 0 || length > output->length ||
+ (index + length) > msblk->bytes_used)
+ goto read_failure;
+
+ for (b = 0; bytes < length; b++, cur_index++) {
+ bh[b] = sb_getblk(sb, cur_index);
+ if (bh[b] == NULL)
+ goto block_release;
+ bytes += msblk->devblksize;
+ }
+ ll_rw_block(REQ_OP_READ, 0, b, bh);
} else {
/*
* Metadata block.
*/
- const u8 *data;
- struct bvec_iter_all iter_all = {};
- struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
-
- if (index + 2 > msblk->bytes_used) {
- res = -EIO;
- goto out;
- }
- res = squashfs_bio_read(sb, index, 2, &bio, &offset);
- if (res)
- goto out;
-
- if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) {
- res = -EIO;
- goto out_free_bio;
- }
- /* Extract the length of the metadata block */
- data = page_address(bvec->bv_page) + bvec->bv_offset;
- length = data[offset];
- if (offset <= bvec->bv_len - 1) {
- length |= data[offset + 1] << 8;
- } else {
- if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) {
- res = -EIO;
- goto out_free_bio;
- }
- data = page_address(bvec->bv_page) + bvec->bv_offset;
- length |= data[0] << 8;
- }
- bio_free_pages(bio);
- bio_put(bio);
+ if ((index + 2) > msblk->bytes_used)
+ goto read_failure;
+ bh[0] = get_block_length(sb, &cur_index, &offset, &length);
+ if (bh[0] == NULL)
+ goto read_failure;
+ b = 1;
+
+ bytes = msblk->devblksize - offset;
compressed = SQUASHFS_COMPRESSED(length);
length = SQUASHFS_COMPRESSED_SIZE(length);
- index += 2;
+ if (next_index)
+ *next_index = index + length + 2;
TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
- compressed ? "" : "un", length);
+ compressed ? "" : "un", length);
+
+ if (length < 0 || length > output->length ||
+ (index + length) > msblk->bytes_used)
+ goto block_release;
+
+ for (; bytes < length; b++) {
+ bh[b] = sb_getblk(sb, ++cur_index);
+ if (bh[b] == NULL)
+ goto block_release;
+ bytes += msblk->devblksize;
+ }
+ ll_rw_block(REQ_OP_READ, 0, b - 1, bh + 1);
}
- if (next_index)
- *next_index = index + length;
- res = squashfs_bio_read(sb, index, length, &bio, &offset);
- if (res)
- goto out;
+ for (i = 0; i < b; i++) {
+ wait_on_buffer(bh[i]);
+ if (!buffer_uptodate(bh[i]))
+ goto block_release;
+ }
if (compressed) {
- if (!msblk->stream) {
- res = -EIO;
- goto out_free_bio;
- }
- res = squashfs_decompress(msblk, bio, offset, length, output);
+ if (!msblk->stream)
+ goto read_failure;
+ length = squashfs_decompress(msblk, bh, b, offset, length,
+ output);
+ if (length < 0)
+ goto read_failure;
} else {
- res = copy_bio_to_actor(bio, output, offset, length);
+ /*
+ * Block is uncompressed.
+ */
+ int in, pg_offset = 0;
+ void *data = squashfs_first_page(output);
+
+ for (bytes = length; k < b; k++) {
+ in = min(bytes, msblk->devblksize - offset);
+ bytes -= in;
+ while (in) {
+ if (pg_offset == PAGE_SIZE) {
+ data = squashfs_next_page(output);
+ pg_offset = 0;
+ }
+ avail = min_t(int, in, PAGE_SIZE -
+ pg_offset);
+ memcpy(data + pg_offset, bh[k]->b_data + offset,
+ avail);
+ in -= avail;
+ pg_offset += avail;
+ offset += avail;
+ }
+ offset = 0;
+ put_bh(bh[k]);
+ }
+ squashfs_finish_page(output);
}
-out_free_bio:
- bio_free_pages(bio);
- bio_put(bio);
-out:
- if (res < 0)
- ERROR("Failed to read block 0x%llx: %d\n", index, res);
+ kfree(bh);
+ return length;
- return res;
+block_release:
+ for (; k < b; k++)
+ put_bh(bh[k]);
+
+read_failure:
+ ERROR("squashfs_read_data failed to read block 0x%llx\n",
+ (unsigned long long) index);
+ kfree(bh);
+ return -EIO;
}
--- a/fs/squashfs/decompressor.h~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/decompressor.h
@@ -10,14 +10,13 @@
* decompressor.h
*/
-#include <linux/bio.h>
-
struct squashfs_decompressor {
void *(*init)(struct squashfs_sb_info *, void *);
void *(*comp_opts)(struct squashfs_sb_info *, void *, int);
void (*free)(void *);
int (*decompress)(struct squashfs_sb_info *, void *,
- struct bio *, int, int, struct squashfs_page_actor *);
+ struct buffer_head **, int, int, int,
+ struct squashfs_page_actor *);
int id;
char *name;
int supported;
--- a/fs/squashfs/decompressor_multi.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/decompressor_multi.c
@@ -6,7 +6,7 @@
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/cpumask.h>
@@ -180,15 +180,14 @@ wait:
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
- int offset, int length,
- struct squashfs_page_actor *output)
+int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
+ int b, int offset, int length, struct squashfs_page_actor *output)
{
int res;
struct squashfs_stream *stream = msblk->stream;
struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream);
res = msblk->decompressor->decompress(msblk, decomp_stream->stream,
- bio, offset, length, output);
+ bh, b, offset, length, output);
put_decomp_stream(decomp_stream, stream);
if (res < 0)
ERROR("%s decompression failed, data probably corrupt\n",
--- a/fs/squashfs/decompressor_multi_percpu.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/decompressor_multi_percpu.c
@@ -75,8 +75,8 @@ void squashfs_decompressor_destroy(struc
}
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
- int offset, int length, struct squashfs_page_actor *output)
+int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
+ int b, int offset, int length, struct squashfs_page_actor *output)
{
struct squashfs_stream *stream;
int res;
@@ -84,7 +84,7 @@ int squashfs_decompress(struct squashfs_
local_lock(&msblk->stream->lock);
stream = this_cpu_ptr(msblk->stream);
- res = msblk->decompressor->decompress(msblk, stream->stream, bio,
+ res = msblk->decompressor->decompress(msblk, stream->stream, bh, b,
offset, length, output);
local_unlock(&msblk->stream->lock);
--- a/fs/squashfs/decompressor_single.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/decompressor_single.c
@@ -7,7 +7,7 @@
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
@@ -59,15 +59,14 @@ void squashfs_decompressor_destroy(struc
}
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
- int offset, int length,
- struct squashfs_page_actor *output)
+int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
+ int b, int offset, int length, struct squashfs_page_actor *output)
{
int res;
struct squashfs_stream *stream = msblk->stream;
mutex_lock(&stream->mutex);
- res = msblk->decompressor->decompress(msblk, stream->stream, bio,
+ res = msblk->decompressor->decompress(msblk, stream->stream, bh, b,
offset, length, output);
mutex_unlock(&stream->mutex);
--- a/fs/squashfs/lz4_wrapper.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/lz4_wrapper.c
@@ -4,7 +4,7 @@
* Phillip Lougher <phillip@squashfs.org.uk>
*/
-#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -89,23 +89,20 @@ static void lz4_free(void *strm)
static int lz4_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct bio *bio, int offset, int length,
+ struct buffer_head **bh, int b, int offset, int length,
struct squashfs_page_actor *output)
{
- struct bvec_iter_all iter_all = {};
- struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
struct squashfs_lz4 *stream = strm;
void *buff = stream->input, *data;
- int bytes = length, res;
+ int avail, i, bytes = length, res;
- while (bio_next_segment(bio, &iter_all)) {
- int avail = min(bytes, ((int)bvec->bv_len) - offset);
-
- data = page_address(bvec->bv_page) + bvec->bv_offset;
- memcpy(buff, data + offset, avail);
+ for (i = 0; i < b; i++) {
+ avail = min(bytes, msblk->devblksize - offset);
+ memcpy(buff, bh[i]->b_data + offset, avail);
buff += avail;
bytes -= avail;
offset = 0;
+ put_bh(bh[i]);
}
res = LZ4_decompress_safe(stream->input, stream->output,
--- a/fs/squashfs/lzo_wrapper.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/lzo_wrapper.c
@@ -9,7 +9,7 @@
*/
#include <linux/mutex.h>
-#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/lzo.h>
@@ -63,24 +63,21 @@ static void lzo_free(void *strm)
static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct bio *bio, int offset, int length,
+ struct buffer_head **bh, int b, int offset, int length,
struct squashfs_page_actor *output)
{
- struct bvec_iter_all iter_all = {};
- struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
struct squashfs_lzo *stream = strm;
void *buff = stream->input, *data;
- int bytes = length, res;
+ int avail, i, bytes = length, res;
size_t out_len = output->length;
- while (bio_next_segment(bio, &iter_all)) {
- int avail = min(bytes, ((int)bvec->bv_len) - offset);
-
- data = page_address(bvec->bv_page) + bvec->bv_offset;
- memcpy(buff, data + offset, avail);
+ for (i = 0; i < b; i++) {
+ avail = min(bytes, msblk->devblksize - offset);
+ memcpy(buff, bh[i]->b_data + offset, avail);
buff += avail;
bytes -= avail;
offset = 0;
+ put_bh(bh[i]);
}
res = lzo1x_decompress_safe(stream->input, (size_t)length,
--- a/fs/squashfs/squashfs.h~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/squashfs.h
@@ -40,8 +40,8 @@ extern void *squashfs_decompressor_setup
/* decompressor_xxx.c */
extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *);
extern void squashfs_decompressor_destroy(struct squashfs_sb_info *);
-extern int squashfs_decompress(struct squashfs_sb_info *, struct bio *,
- int, int, struct squashfs_page_actor *);
+extern int squashfs_decompress(struct squashfs_sb_info *, struct buffer_head **,
+ int, int, int, struct squashfs_page_actor *);
extern int squashfs_max_decompressors(void);
/* export.c */
--- a/fs/squashfs/xz_wrapper.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/xz_wrapper.c
@@ -10,7 +10,7 @@
#include <linux/mutex.h>
-#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include <linux/slab.h>
#include <linux/xz.h>
#include <linux/bitops.h>
@@ -117,12 +117,11 @@ static void squashfs_xz_free(void *strm)
static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct bio *bio, int offset, int length,
+ struct buffer_head **bh, int b, int offset, int length,
struct squashfs_page_actor *output)
{
- struct bvec_iter_all iter_all = {};
- struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
- int total = 0, error = 0;
+ enum xz_ret xz_err;
+ int avail, total = 0, k = 0;
struct squashfs_xz *stream = strm;
xz_dec_reset(stream->state);
@@ -132,23 +131,11 @@ static int squashfs_xz_uncompress(struct
stream->buf.out_size = PAGE_SIZE;
stream->buf.out = squashfs_first_page(output);
- for (;;) {
- enum xz_ret xz_err;
-
- if (stream->buf.in_pos == stream->buf.in_size) {
- const void *data;
- int avail;
-
- if (!bio_next_segment(bio, &iter_all)) {
- /* XZ_STREAM_END must be reached. */
- error = -EIO;
- break;
- }
-
- avail = min(length, ((int)bvec->bv_len) - offset);
- data = page_address(bvec->bv_page) + bvec->bv_offset;
+ do {
+ if (stream->buf.in_pos == stream->buf.in_size && k < b) {
+ avail = min(length, msblk->devblksize - offset);
length -= avail;
- stream->buf.in = data + offset;
+ stream->buf.in = bh[k]->b_data + offset;
stream->buf.in_size = avail;
stream->buf.in_pos = 0;
offset = 0;
@@ -163,17 +150,23 @@ static int squashfs_xz_uncompress(struct
}
xz_err = xz_dec_run(stream->state, &stream->buf);
- if (xz_err == XZ_STREAM_END)
- break;
- if (xz_err != XZ_OK) {
- error = -EIO;
- break;
- }
- }
+
+ if (stream->buf.in_pos == stream->buf.in_size && k < b)
+ put_bh(bh[k++]);
+ } while (xz_err == XZ_OK);
squashfs_finish_page(output);
- return error ? error : total + stream->buf.out_pos;
+ if (xz_err != XZ_STREAM_END || k < b)
+ goto out;
+
+ return total + stream->buf.out_pos;
+
+out:
+ for (; k < b; k++)
+ put_bh(bh[k]);
+
+ return -EIO;
}
const struct squashfs_decompressor squashfs_xz_comp_ops = {
--- a/fs/squashfs/zlib_wrapper.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/zlib_wrapper.c
@@ -10,7 +10,7 @@
#include <linux/mutex.h>
-#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include <linux/slab.h>
#include <linux/zlib.h>
#include <linux/vmalloc.h>
@@ -50,35 +50,21 @@ static void zlib_free(void *strm)
static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct bio *bio, int offset, int length,
+ struct buffer_head **bh, int b, int offset, int length,
struct squashfs_page_actor *output)
{
- struct bvec_iter_all iter_all = {};
- struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
- int zlib_init = 0, error = 0;
+ int zlib_err, zlib_init = 0, k = 0;
z_stream *stream = strm;
stream->avail_out = PAGE_SIZE;
stream->next_out = squashfs_first_page(output);
stream->avail_in = 0;
- for (;;) {
- int zlib_err;
-
- if (stream->avail_in == 0) {
- const void *data;
- int avail;
-
- if (!bio_next_segment(bio, &iter_all)) {
- /* Z_STREAM_END must be reached. */
- error = -EIO;
- break;
- }
-
- avail = min(length, ((int)bvec->bv_len) - offset);
- data = page_address(bvec->bv_page) + bvec->bv_offset;
+ do {
+ if (stream->avail_in == 0 && k < b) {
+ int avail = min(length, msblk->devblksize - offset);
length -= avail;
- stream->next_in = data + offset;
+ stream->next_in = bh[k]->b_data + offset;
stream->avail_in = avail;
offset = 0;
}
@@ -92,28 +78,37 @@ static int zlib_uncompress(struct squash
if (!zlib_init) {
zlib_err = zlib_inflateInit(stream);
if (zlib_err != Z_OK) {
- error = -EIO;
- break;
+ squashfs_finish_page(output);
+ goto out;
}
zlib_init = 1;
}
zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
- if (zlib_err == Z_STREAM_END)
- break;
- if (zlib_err != Z_OK) {
- error = -EIO;
- break;
- }
- }
+
+ if (stream->avail_in == 0 && k < b)
+ put_bh(bh[k++]);
+ } while (zlib_err == Z_OK);
squashfs_finish_page(output);
- if (!error)
- if (zlib_inflateEnd(stream) != Z_OK)
- error = -EIO;
+ if (zlib_err != Z_STREAM_END)
+ goto out;
+
+ zlib_err = zlib_inflateEnd(stream);
+ if (zlib_err != Z_OK)
+ goto out;
+
+ if (k < b)
+ goto out;
+
+ return stream->total_out;
+
+out:
+ for (; k < b; k++)
+ put_bh(bh[k]);
- return error ? error : stream->total_out;
+ return -EIO;
}
const struct squashfs_decompressor squashfs_zlib_comp_ops = {
--- a/fs/squashfs/zstd_wrapper.c~revert-squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/zstd_wrapper.c
@@ -9,7 +9,7 @@
*/
#include <linux/mutex.h>
-#include <linux/bio.h>
+#include <linux/buffer_head.h>
#include <linux/slab.h>
#include <linux/zstd.h>
#include <linux/vmalloc.h>
@@ -59,44 +59,33 @@ static void zstd_free(void *strm)
static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct bio *bio, int offset, int length,
+ struct buffer_head **bh, int b, int offset, int length,
struct squashfs_page_actor *output)
{
struct workspace *wksp = strm;
ZSTD_DStream *stream;
size_t total_out = 0;
- int error = 0;
+ size_t zstd_err;
+ int k = 0;
ZSTD_inBuffer in_buf = { NULL, 0, 0 };
ZSTD_outBuffer out_buf = { NULL, 0, 0 };
- struct bvec_iter_all iter_all = {};
- struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
stream = ZSTD_initDStream(wksp->window_size, wksp->mem, wksp->mem_size);
if (!stream) {
ERROR("Failed to initialize zstd decompressor\n");
- return -EIO;
+ goto out;
}
out_buf.size = PAGE_SIZE;
out_buf.dst = squashfs_first_page(output);
- for (;;) {
- size_t zstd_err;
+ do {
+ if (in_buf.pos == in_buf.size && k < b) {
+ int avail = min(length, msblk->devblksize - offset);
- if (in_buf.pos == in_buf.size) {
- const void *data;
- int avail;
-
- if (!bio_next_segment(bio, &iter_all)) {
- error = -EIO;
- break;
- }
-
- avail = min(length, ((int)bvec->bv_len) - offset);
- data = page_address(bvec->bv_page) + bvec->bv_offset;
length -= avail;
- in_buf.src = data + offset;
+ in_buf.src = bh[k]->b_data + offset;
in_buf.size = avail;
in_buf.pos = 0;
offset = 0;
@@ -108,8 +97,8 @@ static int zstd_uncompress(struct squash
/* Shouldn't run out of pages
* before stream is done.
*/
- error = -EIO;
- break;
+ squashfs_finish_page(output);
+ goto out;
}
out_buf.pos = 0;
out_buf.size = PAGE_SIZE;
@@ -118,20 +107,29 @@ static int zstd_uncompress(struct squash
total_out -= out_buf.pos;
zstd_err = ZSTD_decompressStream(stream, &out_buf, &in_buf);
total_out += out_buf.pos; /* add the additional data produced */
- if (zstd_err == 0)
- break;
- if (ZSTD_isError(zstd_err)) {
- ERROR("zstd decompression error: %d\n",
- (int)ZSTD_getErrorCode(zstd_err));
- error = -EIO;
- break;
- }
- }
+ if (in_buf.pos == in_buf.size && k < b)
+ put_bh(bh[k++]);
+ } while (zstd_err != 0 && !ZSTD_isError(zstd_err));
squashfs_finish_page(output);
- return error ? error : total_out;
+ if (ZSTD_isError(zstd_err)) {
+ ERROR("zstd decompression error: %d\n",
+ (int)ZSTD_getErrorCode(zstd_err));
+ goto out;
+ }
+
+ if (k < b)
+ goto out;
+
+ return (int)total_out;
+
+out:
+ for (; k < b; k++)
+ put_bh(bh[k]);
+
+ return -EIO;
}
const struct squashfs_decompressor squashfs_zstd_comp_ops = {
_
^ permalink raw reply
* + mm-vmstat-fix-proc-sys-vm-stat_refresh-generating-false-warnings.patch added to -mm tree
From: Andrew Morton @ 2020-07-16 23:08 UTC (permalink / raw)
To: guro, hannes, hughd, mhocko, mm-commits
In-Reply-To: <20200703151445.b6a0cfee402c7c5c4651f1b1@linux-foundation.org>
The patch titled
Subject: mm: vmstat: fix /proc/sys/vm/stat_refresh generating false warnings
has been added to the -mm tree. Its filename is
mm-vmstat-fix-proc-sys-vm-stat_refresh-generating-false-warnings.patch
This patch should soon appear at
http://ozlabs.org/~akpm/mmots/broken-out/mm-vmstat-fix-proc-sys-vm-stat_refresh-generating-false-warnings.patch
and later at
http://ozlabs.org/~akpm/mmotm/broken-out/mm-vmstat-fix-proc-sys-vm-stat_refresh-generating-false-warnings.patch
Before you just go and hit "reply", please:
a) Consider who else should be cc'ed
b) Prefer to cc a suitable mailing list as well
c) Ideally: find the original patch on the mailing list and do a
reply-to-all to that, adding suitable additional cc's
*** Remember to use Documentation/process/submit-checklist.rst when testing your code ***
The -mm tree is included into linux-next and is updated
there every 3-4 working days
------------------------------------------------------
From: Roman Gushchin <guro@fb.com>
Subject: mm: vmstat: fix /proc/sys/vm/stat_refresh generating false warnings
I've noticed a number of warnings like "vmstat_refresh: nr_free_cma -5" or
"vmstat_refresh: nr_zone_write_pending -11" on our production hosts. The
numbers of these warnings were relatively low and stable, so it didn't
look like we are systematically leaking the counters. The corresponding
vmstat counters also looked sane.
These warnings are generated by the vmstat_refresh() function, which
assumes that atomic zone and numa counters can't go below zero. However,
on a SMP machine it's not quite right: due to per-cpu caching it can in
theory be as low as -(zone threshold) * NR_CPUs.
For instance, let's say all cma pages are in use and NR_FREE_CMA_PAGES
reached 0. Then we've reclaimed a small number of cma pages on each CPU
except CPU0, so that most percpu NR_FREE_CMA_PAGES counters are slightly
positive (the atomic counter is still 0). Then somebody on CPU0 consumes
all these pages. The number of pages can easily exceed the threshold and
a negative value will be committed to the atomic counter.
To fix the problem and avoid generating false warnings, let's just relax
the condition and warn only if the value is less than minus the maximum
theoretically possible drift value, which is 125 * number of online CPUs.
It will still allow to catch systematic leaks, but will not generate bogus
warnings.
Link: http://lkml.kernel.org/r/20200714173920.3319063-1-guro@fb.com
Signed-off-by: Roman Gushchin <guro@fb.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
Documentation/admin-guide/sysctl/vm.rst | 4 +-
mm/vmstat.c | 30 +++++++++++++---------
2 files changed, 21 insertions(+), 13 deletions(-)
--- a/Documentation/admin-guide/sysctl/vm.rst~mm-vmstat-fix-proc-sys-vm-stat_refresh-generating-false-warnings
+++ a/Documentation/admin-guide/sysctl/vm.rst
@@ -822,8 +822,8 @@ e.g. cat /proc/sys/vm/stat_refresh /proc
As a side-effect, it also checks for negative totals (elsewhere reported
as 0) and "fails" with EINVAL if any are found, with a warning in dmesg.
-(At time of writing, a few stats are known sometimes to be found negative,
-with no ill effects: errors and warnings on these stats are suppressed.)
+(On a SMP machine some stats can temporarily become negative, with no ill
+effects: errors and warnings on these stats are suppressed.)
numa_stat
--- a/mm/vmstat.c~mm-vmstat-fix-proc-sys-vm-stat_refresh-generating-false-warnings
+++ a/mm/vmstat.c
@@ -169,6 +169,8 @@ EXPORT_SYMBOL(vm_node_stat);
#ifdef CONFIG_SMP
+#define MAX_THRESHOLD 125
+
int calculate_pressure_threshold(struct zone *zone)
{
int threshold;
@@ -186,11 +188,9 @@ int calculate_pressure_threshold(struct
threshold = max(1, (int)(watermark_distance / num_online_cpus()));
/*
- * Maximum threshold is 125
+ * Threshold is capped by MAX_THRESHOLD
*/
- threshold = min(125, threshold);
-
- return threshold;
+ return min(MAX_THRESHOLD, threshold);
}
int calculate_normal_threshold(struct zone *zone)
@@ -610,6 +610,9 @@ void dec_node_page_state(struct page *pa
}
EXPORT_SYMBOL(dec_node_page_state);
#else
+
+#define MAX_THRESHOLD 0
+
/*
* Use interrupt disable to serialize counter updates
*/
@@ -1810,7 +1813,7 @@ static void refresh_vm_stats(struct work
int vmstat_refresh(struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
- long val;
+ long val, max_drift;
int err;
int i;
@@ -1821,17 +1824,22 @@ int vmstat_refresh(struct ctl_table *tab
* pages, immediately after running a test. /proc/sys/vm/stat_refresh,
* which can equally be echo'ed to or cat'ted from (by root),
* can be used to update the stats just before reading them.
- *
- * Oh, and since global_zone_page_state() etc. are so careful to hide
- * transiently negative values, report an error here if any of
- * the stats is negative, so we know to go looking for imbalance.
*/
err = schedule_on_each_cpu(refresh_vm_stats);
if (err)
return err;
+
+ /*
+ * Since global_zone_page_state() etc. are so careful to hide
+ * transiently negative values, report an error here if any of
+ * the stats is negative and are less than the maximum drift value,
+ * so we know to go looking for imbalance.
+ */
+ max_drift = num_online_cpus() * MAX_THRESHOLD;
+
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
val = atomic_long_read(&vm_zone_stat[i]);
- if (val < 0) {
+ if (val < -max_drift) {
pr_warn("%s: %s %ld\n",
__func__, zone_stat_name(i), val);
err = -EINVAL;
@@ -1840,7 +1848,7 @@ int vmstat_refresh(struct ctl_table *tab
#ifdef CONFIG_NUMA
for (i = 0; i < NR_VM_NUMA_STAT_ITEMS; i++) {
val = atomic_long_read(&vm_numa_stat[i]);
- if (val < 0) {
+ if (val < -max_drift) {
pr_warn("%s: %s %ld\n",
__func__, numa_stat_name(i), val);
err = -EINVAL;
_
Patches currently in -mm which might be from guro@fb.com are
mm-kmem-make-memcg_kmem_enabled-irreversible.patch
mm-memcg-factor-out-memcg-and-lruvec-level-changes-out-of-__mod_lruvec_state.patch
mm-memcg-prepare-for-byte-sized-vmstat-items.patch
mm-memcg-convert-vmstat-slab-counters-to-bytes.patch
mm-slub-implement-slub-version-of-obj_to_index.patch
mm-memcg-slab-obj_cgroup-api.patch
mm-memcg-slab-allocate-obj_cgroups-for-non-root-slab-pages.patch
mm-memcg-slab-save-obj_cgroup-for-non-root-slab-objects.patch
mm-memcg-slab-charge-individual-slab-objects-instead-of-pages.patch
mm-memcg-slab-deprecate-memorykmemslabinfo.patch
mm-memcg-slab-move-memcg_kmem_bypass-to-memcontrolh.patch
mm-memcg-slab-use-a-single-set-of-kmem_caches-for-all-accounted-allocations.patch
mm-memcg-slab-simplify-memcg-cache-creation.patch
mm-memcg-slab-remove-memcg_kmem_get_cache.patch
mm-memcg-slab-deprecate-slab_root_caches.patch
mm-memcg-slab-remove-redundant-check-in-memcg_accumulate_slabinfo.patch
mm-memcg-slab-use-a-single-set-of-kmem_caches-for-all-allocations.patch
kselftests-cgroup-add-kernel-memory-accounting-tests.patch
tools-cgroup-add-memcg_slabinfopy-tool.patch
percpu-return-number-of-released-bytes-from-pcpu_free_area.patch
mm-memcg-percpu-account-percpu-memory-to-memory-cgroups.patch
mm-memcg-percpu-per-memcg-percpu-memory-statistics.patch
mm-memcg-percpu-per-memcg-percpu-memory-statistics-v3.patch
mm-memcg-charge-memcg-percpu-memory-to-the-parent-cgroup.patch
kselftests-cgroup-add-perpcu-memory-accounting-test.patch
mm-memcg-slab-remove-unused-argument-by-charge_slab_page.patch
mm-slab-rename-uncharge_slab_page-to-unaccount_slab_page.patch
mm-kmem-switch-to-static_branch_likely-in-memcg_kmem_enabled.patch
mm-memcontrol-avoid-workload-stalls-when-lowering-memoryhigh.patch
mm-vmstat-fix-proc-sys-vm-stat_refresh-generating-false-warnings.patch
^ permalink raw reply
* Re: [PATCH net] net: dsa: link interfaces with the DSA master to get rid of lockdep warnings
From: Jakub Kicinski @ 2020-07-16 23:06 UTC (permalink / raw)
To: Vladimir Oltean
Cc: davem, netdev, andrew, f.fainelli, vivien.didelot, xiyou.wangcong,
ap420073
In-Reply-To: <20200713162443.2510682-1-olteanv@gmail.com>
On Mon, 13 Jul 2020 19:24:43 +0300 Vladimir Oltean wrote:
> diff --git a/net/dsa/slave.c b/net/dsa/slave.c
> index 743caabeaaa6..a951b2a7d79a 100644
> --- a/net/dsa/slave.c
> +++ b/net/dsa/slave.c
> @@ -1994,6 +1994,13 @@ int dsa_slave_create(struct dsa_port *port)
> ret, slave_dev->name);
> goto out_phy;
> }
> + rtnl_lock();
> + ret = netdev_upper_dev_link(master, slave_dev, NULL);
> + rtnl_unlock();
> + if (ret) {
> + unregister_netdevice(slave_dev);
The error handling here looks sketchy.
First of all please move this unregister to the error path below, not
inside the body of the if.
Secondly as a rule of thumb the error path should resemble the destroy
function.
Here we have :
unregister_netdevice(slave_dev);
out_phy:
rtnl_lock();
phylink_disconnect_phy(p->dp->pl);
rtnl_unlock();
phylink_destroy(p->dp->pl);
out_gcells:
gro_cells_destroy(&p->gcells);
out_free:
free_percpu(p->stats64);
free_netdev(slave_dev);
port->slave = NULL;
return ret;
vs.
netif_carrier_off(slave_dev);
rtnl_lock();
phylink_disconnect_phy(dp->pl);
rtnl_unlock();
dsa_slave_notify(slave_dev, DSA_PORT_UNREGISTER);
unregister_netdev(slave_dev);
phylink_destroy(dp->pl);
gro_cells_destroy(&p->gcells);
free_percpu(p->stats64);
free_netdev(slave_dev);
Ordering is different, plus you're missing the dsa_slave_notify() and
netif_carrier_off().
> + goto out_phy;
> + }
>
> return 0;
>
> @@ -2013,11 +2020,13 @@ int dsa_slave_create(struct dsa_port *port)
>
> void dsa_slave_destroy(struct net_device *slave_dev)
> {
> + struct net_device *master = dsa_slave_to_master(slave_dev);
> struct dsa_port *dp = dsa_slave_to_port(slave_dev);
> struct dsa_slave_priv *p = netdev_priv(slave_dev);
>
> netif_carrier_off(slave_dev);
> rtnl_lock();
> + netdev_upper_dev_unlink(master, slave_dev);
> phylink_disconnect_phy(dp->pl);
> rtnl_unlock();
^ permalink raw reply
* Question about NUMA distance calculation in powerpc/mm/numa.c
From: Daniel Henrique Barboza @ 2020-07-16 23:13 UTC (permalink / raw)
To: linuxppc-dev
Hello,
I didn't find an explanation about the 'double the distance' logic in
'git log' or anywhere in the kernel docs:
(arch/powerpc/mm/numa.c, __node_distance()):
for (i = 0; i < distance_ref_points_depth; i++) {
if (distance_lookup_table[a][i] == distance_lookup_table[b][i])
break;
/* Double the distance for each NUMA level */
distance *= 2;
}
For reference, the commit that added it:
commit 41eab6f88f24124df89e38067b3766b7bef06ddb
Author: Anton Blanchard <anton@samba.org>
Date: Sun May 16 20:22:31 2010 +0000
powerpc/numa: Use form 1 affinity to setup node distance
Is there a technical reason for the distance being calculated as the double
for each NUMA level?
The reason I'm asking is because of the QEMU/Libvirt capability to define NUMA
node distances in the VMs. For x86, an user is capable of setting any distance
values to the NUMA topology due to how ACPI SLIT works.
The user, of course, wants the pseries guest to behave the same way. The best
we can do for now is document why this will not happen. I'll document the
limitations imposed by the design itself (how ibm,associativity-reference-points
is capped to MAX_DISTANCE_REF_POINTS and so on). I also would like to document
that the pseries kernel will double the distance for each NUMA level, and for
that it would be nice to provide an actual reason for that to happen, if
there is any.
Thanks,
Daniel
^ permalink raw reply
* [PATCH v8 4/5] remoteproc: Add inline coredump functionality
From: Rishabh Bhatnagar @ 2020-07-16 22:20 UTC (permalink / raw)
To: linux-remoteproc, linux-kernel
Cc: bjorn.andersson, mathieu.poirier, sibis, tsoni, psodagud, sidgup,
Rishabh Bhatnagar
In-Reply-To: <1594938035-7327-1-git-send-email-rishabhb@codeaurora.org>
The current coredump implementation uses vmalloc area to copy
all the segments. But this might put strain on low memory targets
as the firmware size sometimes is in tens of MBs. The situation
becomes worse if there are multiple remote processors undergoing
recovery at the same time. This patch adds inline coredump
functionality that avoids extra memory usage. This requires
recovery to be halted until data is read by userspace and free
function is called.
Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>
Tested-by: Sibi Sankar <sibis@codeaurora.org>
---
drivers/remoteproc/remoteproc_coredump.c | 156 +++++++++++++++++++++++++++----
include/linux/remoteproc.h | 16 ++++
2 files changed, 154 insertions(+), 18 deletions(-)
diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c
index 390f563..bb15a29 100644
--- a/drivers/remoteproc/remoteproc_coredump.c
+++ b/drivers/remoteproc/remoteproc_coredump.c
@@ -5,6 +5,7 @@
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
+#include <linux/completion.h>
#include <linux/devcoredump.h>
#include <linux/device.h>
#include <linux/kernel.h>
@@ -12,6 +13,12 @@
#include "remoteproc_internal.h"
#include "remoteproc_elf_helpers.h"
+struct rproc_coredump_state {
+ struct rproc *rproc;
+ void *header;
+ struct completion dump_done;
+};
+
/**
* rproc_coredump_cleanup() - clean up dump_segments list
* @rproc: the remote processor handle
@@ -115,12 +122,110 @@ int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine)
}
EXPORT_SYMBOL(rproc_coredump_set_elf_info);
+static void rproc_coredump_free(void *data)
+{
+ struct rproc_coredump_state *dump_state = data;
+
+ vfree(dump_state->header);
+ complete(&dump_state->dump_done);
+}
+
+static void *rproc_coredump_find_segment(loff_t user_offset,
+ struct list_head *segments,
+ size_t *data_left)
+{
+ struct rproc_dump_segment *segment;
+
+ list_for_each_entry(segment, segments, node) {
+ if (user_offset < segment->size) {
+ *data_left = segment->size - user_offset;
+ return segment;
+ }
+ user_offset -= segment->size;
+ }
+
+ *data_left = 0;
+ return NULL;
+}
+
+static void rproc_copy_segment(struct rproc *rproc, void *dest,
+ struct rproc_dump_segment *segment,
+ size_t offset, size_t size)
+{
+ void *ptr;
+
+ if (segment->dump) {
+ segment->dump(rproc, segment, dest, offset, size);
+ } else {
+ ptr = rproc_da_to_va(rproc, segment->da + offset, size);
+ if (!ptr) {
+ dev_err(&rproc->dev,
+ "invalid copy request for segment %pad with offset %zu and size %zu)\n",
+ &segment->da, offset, size);
+ memset(dest, 0xff, size);
+ } else {
+ memcpy(dest, ptr, size);
+ }
+ }
+}
+
+static ssize_t rproc_coredump_read(char *buffer, loff_t offset, size_t count,
+ void *data, size_t header_sz)
+{
+ size_t seg_data, bytes_left = count;
+ ssize_t copy_sz;
+ struct rproc_dump_segment *seg;
+ struct rproc_coredump_state *dump_state = data;
+ struct rproc *rproc = dump_state->rproc;
+ void *elfcore = dump_state->header;
+
+ /* Copy the vmalloc'ed header first. */
+ if (offset < header_sz) {
+ copy_sz = memory_read_from_buffer(buffer, count, &offset,
+ elfcore, header_sz);
+
+ return copy_sz;
+ }
+
+ /*
+ * Find out the segment memory chunk to be copied based on offset.
+ * Keep copying data until count bytes are read.
+ */
+ while (bytes_left) {
+ seg = rproc_coredump_find_segment(offset - header_sz,
+ &rproc->dump_segments,
+ &seg_data);
+ /* EOF check */
+ if (!seg) {
+ dev_info(&rproc->dev, "Ramdump done, %lld bytes read",
+ offset);
+ break;
+ }
+
+ copy_sz = min_t(size_t, bytes_left, seg_data);
+
+ rproc_copy_segment(rproc, buffer, seg, seg->size - seg_data,
+ copy_sz);
+
+ offset += copy_sz;
+ buffer += copy_sz;
+ bytes_left -= copy_sz;
+ }
+
+ return count - bytes_left;
+}
+
/**
* rproc_coredump() - perform coredump
* @rproc: rproc handle
*
* This function will generate an ELF header for the registered segments
- * and create a devcoredump device associated with rproc.
+ * and create a devcoredump device associated with rproc. Based on the
+ * coredump configuration this function will directly copy the segments
+ * from device memory to userspace or copy segments from device memory to
+ * a separate buffer, which can then be read by userspace.
+ * The first approach avoids using extra vmalloc memory. But it will stall
+ * recovery flow until dump is read by userspace.
*/
void rproc_coredump(struct rproc *rproc)
{
@@ -130,11 +235,13 @@ void rproc_coredump(struct rproc *rproc)
size_t data_size;
size_t offset;
void *data;
- void *ptr;
u8 class = rproc->elf_class;
int phnum = 0;
+ struct rproc_coredump_state dump_state;
+ enum rproc_dump_mechanism dump_conf = rproc->dump_conf;
- if (list_empty(&rproc->dump_segments))
+ if (list_empty(&rproc->dump_segments) ||
+ dump_conf == RPROC_COREDUMP_DISABLED)
return;
if (class == ELFCLASSNONE) {
@@ -144,7 +251,14 @@ void rproc_coredump(struct rproc *rproc)
data_size = elf_size_of_hdr(class);
list_for_each_entry(segment, &rproc->dump_segments, node) {
- data_size += elf_size_of_phdr(class) + segment->size;
+ /*
+ * For default configuration buffer includes headers & segments.
+ * For inline dump buffer just includes headers as segments are
+ * directly read from device memory.
+ */
+ data_size += elf_size_of_phdr(class);
+ if (dump_conf == RPROC_COREDUMP_DEFAULT)
+ data_size += segment->size;
phnum++;
}
@@ -183,23 +297,29 @@ void rproc_coredump(struct rproc *rproc)
elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
elf_phdr_set_p_align(class, phdr, 0);
- if (segment->dump) {
- segment->dump(rproc, segment, data + offset, 0, segment->size);
- } else {
- ptr = rproc_da_to_va(rproc, segment->da, segment->size);
- if (!ptr) {
- dev_err(&rproc->dev,
- "invalid coredump segment (%pad, %zu)\n",
- &segment->da, segment->size);
- memset(data + offset, 0xff, segment->size);
- } else {
- memcpy(data + offset, ptr, segment->size);
- }
- }
+ if (dump_conf == RPROC_COREDUMP_DEFAULT)
+ rproc_copy_segment(rproc, data + offset, segment, 0,
+ segment->size);
offset += elf_phdr_get_p_filesz(class, phdr);
phdr += elf_size_of_phdr(class);
}
+ if (dump_conf == RPROC_COREDUMP_DEFAULT) {
+ dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
+ return;
+ }
+
+ /* Initialize the dump state struct to be used by rproc_coredump_read */
+ dump_state.rproc = rproc;
+ dump_state.header = data;
+ init_completion(&dump_state.dump_done);
+
+ dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, GFP_KERNEL,
+ rproc_coredump_read, rproc_coredump_free);
- dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
+ /*
+ * Wait until the dump is read and free is called. Data is freed
+ * by devcoredump framework automatically after 5 minutes.
+ */
+ wait_for_completion(&dump_state.dump_done);
}
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index eb08139..38d037d 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -435,6 +435,20 @@ enum rproc_crash_type {
};
/**
+ * enum rproc_dump_mechanism - Coredump options for core
+ * @RPROC_COREDUMP_DEFAULT: Copy dump to separate buffer and carry on with
+ recovery
+ * @RPROC_COREDUMP_INLINE: Read segments directly from device memory. Stall
+ recovery until all segments are read
+ * @RPROC_COREDUMP_DISABLED: Don't perform any dump
+ */
+enum rproc_dump_mechanism {
+ RPROC_COREDUMP_DEFAULT,
+ RPROC_COREDUMP_INLINE,
+ RPROC_COREDUMP_DISABLED,
+};
+
+/**
* struct rproc_dump_segment - segment info from ELF header
* @node: list node related to the rproc segment list
* @da: device address of the segment
@@ -466,6 +480,7 @@ struct rproc_dump_segment {
* @dev: virtual device for refcounting and common remoteproc behavior
* @power: refcount of users who need this rproc powered up
* @state: state of the device
+ * @dump_conf: Currently selected coredump configuration
* @lock: lock which protects concurrent manipulations of the rproc
* @dbg_dir: debugfs directory of this rproc device
* @traces: list of trace buffers
@@ -499,6 +514,7 @@ struct rproc {
struct device dev;
atomic_t power;
unsigned int state;
+ enum rproc_dump_mechanism dump_conf;
struct mutex lock;
struct dentry *dbg_dir;
struct list_head traces;
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* [PATCH v8 0/5] Extend coredump functionality
From: Rishabh Bhatnagar @ 2020-07-16 22:20 UTC (permalink / raw)
To: linux-remoteproc, linux-kernel
Cc: bjorn.andersson, mathieu.poirier, sibis, tsoni, psodagud, sidgup,
Rishabh Bhatnagar
This patch series moves the coredump functionality to a separate
file and adds "inline" coredump feature. Inline coredump directly
copies segments from device memory during coredump to userspace.
This avoids extra memory usage at the cost of speed. Recovery is
stalled until all data is read by userspace.
This patchset also includes Sibi Sankar's patch to deal with chunk sizes
lesser than segment size to make inline coredump work for modem.
https://patchwork.kernel.org/patch/11637157/
Changelog:
v8 -> v7:
- Split out the qcom_q6v5_mss refactoring into a new patch
- Remove zero size check in dump_segment function for mss
- Remove segment number being passed as private member for the segment
- Free the memory used by dump state header before signalling completion
v7 -> v6:
- Include Sibi's patch as part of this patchset
- Add a linefeed when displaying coredump conf in debugfs
- Fix a typo in remoteproc.h
v6 -> v5:
- Fix unsigned comaprison with negative bug found on gcc-9.3.0
v5 -> v4:
- Rebase on top of linux-next
- Modify qcom_q6v5_mss driver as a result of rebasing on latest tip.
v4 -> v3:
- Write a helper function to copy segment memory for every dump format
- Change segment dump fn to add offset and size adn covert mss driver
v3 -> v2:
- Move entire coredump functionality to remoteproc_coredump.c
- Modify rproc_coredump to perform dump according to conf. set by userspace
- Move the userspace configuration to debugfs from sysfs.
- Keep the default coredump implementation as is
v2 -> v1:
- Introduce new file for coredump.
- Add userspace sysfs configuration for dump type.
Rishabh Bhatnagar (4):
remoteproc: Move coredump functionality to a new file
remoteproc: Add size and offset arguments to segment dump function
remoteproc: Add inline coredump functionality
remoteproc: Add coredump debugfs entry
Sibi Sankar (1):
remoteproc: qcom_q6v5_mss: Replace mask based tracking with size
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/qcom_q6v5_mss.c | 25 ++-
drivers/remoteproc/remoteproc_core.c | 191 ------------------
drivers/remoteproc/remoteproc_coredump.c | 325 +++++++++++++++++++++++++++++++
drivers/remoteproc/remoteproc_debugfs.c | 90 +++++++++
drivers/remoteproc/remoteproc_internal.h | 4 +
include/linux/remoteproc.h | 21 +-
7 files changed, 451 insertions(+), 206 deletions(-)
create mode 100644 drivers/remoteproc/remoteproc_coredump.c
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply
* Re: [dpdk-dev] [PATCH] net/bnxt: remove unneeded experimental build flag
From: Ajit Khaparde @ 2020-07-16 23:14 UTC (permalink / raw)
To: David Marchand
Cc: dpdk-dev, Ferruh Yigit, Somnath Kotur, Venkat Duvvuru, Kalesh AP
In-Reply-To: <CACZ4nhtd5GPsuQcqtE=Q2rWCLQhMAF+FRVSooS3Q3q3SSV0Vqw@mail.gmail.com>
On Thu, Jul 16, 2020 at 3:50 PM Ajit Khaparde <ajit.khaparde@broadcom.com>
wrote:
>
> On Thu, Jul 16, 2020 at 12:26 AM David Marchand <david.marchand@redhat.com>
> wrote:
>
>> -DALLOW_EXPERIMENTAL_API is always set for in-tree compilation.
>> See https://git.dpdk.org/dpdk/commit/?id=acec04c4b2f5
>>
>> Fixes: 322bd6e70272 ("net/bnxt: add port representor infrastructure")
>>
>> Signed-off-by: David Marchand <david.marchand@redhat.com>
>>
> Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
>
Applied to dpdk-next-net-brcm. Thanks
>
>
>> ---
>> drivers/net/bnxt/Makefile | 1 -
>> 1 file changed, 1 deletion(-)
>>
>> diff --git a/drivers/net/bnxt/Makefile b/drivers/net/bnxt/Makefile
>> index c54fd108d1..2c4cdd1c40 100644
>> --- a/drivers/net/bnxt/Makefile
>> +++ b/drivers/net/bnxt/Makefile
>> @@ -14,7 +14,6 @@ LIB = librte_pmd_bnxt.a
>> EXPORT_MAP := rte_pmd_bnxt_version.map
>>
>> CFLAGS += -O3
>> -CFLAGS += -DALLOW_EXPERIMENTAL_API
>> CFLAGS += $(WERROR_FLAGS)
>> LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
>> LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
>> --
>> 2.23.0
>>
>>
^ permalink raw reply
* Re: [PATCH v5 15/22] fsnotify: send event with parent/name info to sb/mount/non-dir marks
From: Jan Kara @ 2020-07-16 22:34 UTC (permalink / raw)
To: Amir Goldstein; +Cc: Jan Kara, linux-fsdevel
In-Reply-To: <CAOQ4uxiS2zNkVQZjcErmqq2OSXdfk2_H+gDyRWEAdjzbM+qipg@mail.gmail.com>
On Thu 16-07-20 21:42:20, Amir Goldstein wrote:
> On Thu, Jul 16, 2020 at 8:57 PM Jan Kara <jack@suse.cz> wrote:
> >
> > On Thu 16-07-20 20:20:04, Amir Goldstein wrote:
> > > On Thu, Jul 16, 2020 at 8:01 PM Jan Kara <jack@suse.cz> wrote:
> > > >
> > > > On Thu 16-07-20 11:42:23, Amir Goldstein wrote:
> > > > > Similar to events "on child" to watching directory, send event "on child"
> > > > > with parent/name info if sb/mount/non-dir marks are interested in
> > > > > parent/name info.
> > > > >
> > > > > The FS_EVENT_ON_CHILD flag can be set on sb/mount/non-dir marks to specify
> > > > > interest in parent/name info for events on non-directory inodes.
> > > > >
> > > > > Events on "orphan" children (disconnected dentries) are sent without
> > > > > parent/name info.
> > > > >
> > > > > Events on direcories are send with parent/name info only if the parent
> > > > > directory is watching.
> > > > >
> > > > > Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> > > >
> > > > Hum, doesn't this break ignore mask handling in
> > > > fanotify_group_event_mask()? Because parent's ignore mask will be included
> > > > even though parent is added into the iter only to carry the parent info...
> > > >
> > >
> > > Hmm, break ignore mask handling? or fix it?
> > >
> > > Man page said:
> > > "Having these two types of masks permits a mount point or directory to be
> > > marked for receiving events, while at the same time ignoring events for
> > > specific objects under that mount point or directory."
> >
> > Right, but presumably that speaks of the case of a mark where the parent
> > has FS_EVENT_ON_CHILD set. For case of parent watching events of a child, I
> > agree it makes sense to apply ignore masks of both the parent and the child.
> >
> > > The author did not say what to expect from marking a mount and ignoring
> > > a directory.
> >
> > Yes and I'd expect to apply ignore mask on events for that directory but
> > not for events on files in that directory... Even more so because this will
> > be currently inconsistent wrt whether the child is dir (parent's ignore mask
> > does not apply) or file (parent's ignore mask does apply).
> >
>
> Indeed. For that I used this trick in my POC:
>
> /* Set the mark mask, so fsnotify_parent() will find this mark */
> ovm->fsn_mark.mask = mask | FS_EVENT_ON_CHILD;
> ovm->fsn_mark.ignored_mask = mask;
>
> It's not how users are expected to configure an ignored mask on children
> but we can work the ignored mask information into the object mask, like
> I already did w.r.t FS_MODIFY and get the same result without the hack.
OK, nice trick but for this series, I'd like to keep the original ignore
mask behavior (bug to bug compatibility) or possibly let parent's ignore
mask be applied only for events being sent to the parent due to its
FS_EVENT_ON_CHILD. Can you please fix that up? I won't get to it before I
leave for vacation but once I return, I'd like to just pick the fixed up
commit and push everything to linux-next... Thanks!
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH v4 bpf-next 10/14] bpf: Add d_path helper
From: KP Singh @ 2020-07-16 23:13 UTC (permalink / raw)
To: Jiri Olsa, Andrii Nakryiko
Cc: Jiri Olsa, Alexei Starovoitov, Daniel Borkmann, Networking, bpf,
Song Liu, Yonghong Song, Martin KaFai Lau, David Miller,
John Fastabend, Wenbo Zhang, Andrii Nakryiko, Brendan Gregg,
Florent Revest, Al Viro, Florent Revest
In-Reply-To: <20200628194242.GB2988321@krava>
On 6/28/20 9:42 PM, Jiri Olsa wrote:
> On Fri, Jun 26, 2020 at 01:38:27PM -0700, Andrii Nakryiko wrote:
>> On Thu, Jun 25, 2020 at 4:49 PM Jiri Olsa <jolsa@kernel.org> wrote:
>>>
>>> Adding d_path helper function that returns full path
>>> for give 'struct path' object, which needs to be the
>>> kernel BTF 'path' object.
>>>
>>> The helper calls directly d_path function.
>>>
>>> Updating also bpf.h tools uapi header and adding
>>> 'path' to bpf_helpers_doc.py script.
>>>
>>> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
>>> ---
>>> include/uapi/linux/bpf.h | 14 +++++++++-
>>> kernel/trace/bpf_trace.c | 47 ++++++++++++++++++++++++++++++++++
>>> scripts/bpf_helpers_doc.py | 2 ++
>>> tools/include/uapi/linux/bpf.h | 14 +++++++++-
>>> 4 files changed, 75 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
>>> index 0cb8ec948816..23274c81f244 100644
>>> --- a/include/uapi/linux/bpf.h
>>> +++ b/include/uapi/linux/bpf.h
>>> @@ -3285,6 +3285,17 @@ union bpf_attr {
>>> * Dynamically cast a *sk* pointer to a *udp6_sock* pointer.
>>> * Return
>>> * *sk* if casting is valid, or NULL otherwise.
>>> + *
>>> + * int bpf_d_path(struct path *path, char *buf, u32 sz)
>>> + * Description
>>> + * Return full path for given 'struct path' object, which
>>> + * needs to be the kernel BTF 'path' object. The path is
>>> + * returned in buffer provided 'buf' of size 'sz'.
>>> + *
>>> + * Return
>>> + * length of returned string on success, or a negative
>>> + * error in case of failure
>>
>> It's important to note whether string is always zero-terminated (I'm
>> guessing it is, right?).
>
> right, will add
Also note that bpf_probe_read_{kernel, user}_str return the length including
the NUL byte:
* Return
* On success, the strictly positive length of the string,
* including the trailing NUL character. On error, a negative
* value.
It would be good to keep this uniform. So you will need a len += 1 here as well.
- KP
>
>>
>>> + *
>>> */
>>> #define __BPF_FUNC_MAPPER(FN) \
>>> FN(unspec), \
>>> @@ -3427,7 +3438,8 @@ union bpf_attr {
>>> FN(skc_to_tcp_sock), \
>>> FN(skc_to_tcp_timewait_sock), \
>>> FN(skc_to_tcp_request_sock), \
>>> - FN(skc_to_udp6_sock),
>>> + FN(skc_to_udp6_sock), \
>>> + FN(d_path),
>>>
>>> /* integer value in 'imm' field of BPF_CALL instruction selects which helper
>>> * function eBPF program intends to call
>>> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
>>> index b124d468688c..6f31e21565b6 100644
>>> --- a/kernel/trace/bpf_trace.c
>>> +++ b/kernel/trace/bpf_trace.c
>>> @@ -1060,6 +1060,51 @@ static const struct bpf_func_proto bpf_send_signal_thread_proto = {
>>> .arg1_type = ARG_ANYTHING,
>>> };
>>>
>>> +BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz)
>>> +{
>>> + char *p = d_path(path, buf, sz - 1);
>>> + int len;
>>> +
>>> + if (IS_ERR(p)) {
>>> + len = PTR_ERR(p);
>>> + } else {
>>> + len = strlen(p);
>>> + if (len && p != buf) {
>>> + memmove(buf, p, len);
>>> + buf[len] = 0;
>>
>> if len above is zero, you won't zero-terminate it, so probably better
>> to move buf[len] = 0 out of if to do unconditionally
>
> good catch, will change
>
>>
>>> + }
>>> + }
>>> +
>>> + return len;
>>> +}
>>> +
>>> +BTF_SET_START(btf_whitelist_d_path)
>>> +BTF_ID(func, vfs_truncate)
>>> +BTF_ID(func, vfs_fallocate)
>>> +BTF_ID(func, dentry_open)
>>> +BTF_ID(func, vfs_getattr)
>>> +BTF_ID(func, filp_close)
>>> +BTF_SET_END(btf_whitelist_d_path)
>>> +
>>> +static bool bpf_d_path_allowed(const struct bpf_prog *prog)
>>> +{
>>> + return btf_id_set_contains(&btf_whitelist_d_path, prog->aux->attach_btf_id);
>>> +}
>>> +
>>
>> This looks pretty great and clean, considering what's happening under
>> the covers. Nice work, thanks a lot!
>>
>>> +BTF_ID_LIST(bpf_d_path_btf_ids)
>>> +BTF_ID(struct, path)
>>
>> this is a bit more confusing to read and error-prone, but I couldn't
>> come up with any better way to do this... Still better than
>> alternatives.
>>
>>> +
>>> +static const struct bpf_func_proto bpf_d_path_proto = {
>>> + .func = bpf_d_path,
>>> + .gpl_only = true,
>>
>> Does it have to be GPL-only? What's the criteria? Sorry if this was
>> brought up previously.
>
> I don't think it's needed to be gpl_only, I'll set it to false
>
> thanks,
> jirka
>
^ permalink raw reply
* Re: [PATCH 2/2] dt-bindings: net: dsa: qca8k: Add PORT0_PAD_CTRL properties
From: Andrew Lunn @ 2020-07-16 22:32 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Matthew Hagan, Vivien Didelot, Florian Fainelli, David S. Miller,
linux, netdev, linux-kernel, John Crispin, Jonathan McDowell,
Rob Herring, devicetree
In-Reply-To: <20200716150925.0f3e01b8@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com>
On Thu, Jul 16, 2020 at 03:09:25PM -0700, Jakub Kicinski wrote:
> On Mon, 13 Jul 2020 21:50:26 +0100 Matthew Hagan wrote:
> > Add names and decriptions of additional PORT0_PAD_CTRL properties.
> >
> > Signed-off-by: Matthew Hagan <mnhagan88@gmail.com>
> > ---
> > Documentation/devicetree/bindings/net/dsa/qca8k.txt | 8 ++++++++
> > 1 file changed, 8 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/net/dsa/qca8k.txt b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
> > index ccbc6d89325d..3d34c4f2e891 100644
> > --- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt
> > +++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt
> > @@ -13,6 +13,14 @@ Optional properties:
> >
> > - reset-gpios: GPIO to be used to reset the whole device
> >
> > +Optional MAC configuration properties:
> > +
> > +- qca,exchange-mac0-mac6: If present, internally swaps MAC0 and MAC6.
>
> Perhaps we can say a little more here?
>
> > +- qca,sgmii-rxclk-falling-edge: If present, sets receive clock phase to
> > + falling edge.
> > +- qca,sgmii-txclk-falling-edge: If present, sets transmit clock phase to
> > + falling edge.
>
> These are not something that other vendors may implement and therefore
> something we may want to make generic? Andrew?
I've never seen any other vendor implement this. Which to me makes me
think this is a vendor extension, to Ciscos vendor extension of
1000BaseX.
Matthew, do you have a real use cases of these? I don't see a DT patch
making use of them. And if you do, what is the PHY on the other end
which also allows you to invert the clocks?
Andrew
^ permalink raw reply
* Re: Linux kernel in-tree Rust support
From: Josh Triplett @ 2020-07-16 23:12 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Adrian Bunk, Nick Desaulniers, alex.gaynor, geofft, jbaublitz,
Masahiro Yamada, Linus Torvalds, Greg KH, Miguel Ojeda,
Steven Rostedt, LKML, clang-built-linux
In-Reply-To: <CAK8P3a20UQvQO0U=p1kBEUvRdwm8VFBa31aCe7C70hwTzcu_yw@mail.gmail.com>
On Thu, Jul 16, 2020 at 03:06:01PM +0200, Arnd Bergmann wrote:
> On Sun, Jul 12, 2020 at 9:39 PM Josh Triplett <josh@joshtriplett.org> wrote:
> > On Sun, Jul 12, 2020 at 03:31:51PM +0300, Adrian Bunk wrote:
> > >
> > > As an example:
> > > Ubuntu LTS releases upgrade to a new Rust version every 1-2 months.
> > > Ubuntu 16.04 started with Rust 1.7.0 and is now at Rust 1.41.0.
> > >
> > > It would not sound good to me if security updates of distribution
> > > kernels might additionally end up using a different version of the
> > > Rust compiler - the toolchain for the kernel should be stable.
> > >
> > > Would Rust usage in the kernel require distributions to ship
> > > a "Rust for Firefox" and a "Rust for the kernel"?
> >
> > Rust has hard stability guarantees when upgrading from one stable
> > version to the next. If code compiles with a given stable version of
> > Rust, it'll compile with a newer stable version of Rust. Given that, a
> > stable distribution will just need a single sufficiently up-to-date Rust
> > that meets the minimum version requirements of both Firefox and Linux.
> >
> > (That would not apply if the kernel used nightly Rust, since
> > nightly-only features are allowed to change before becoming stable;
> > that's one reason why we should use stable Rust, and try to get Firefox
> > to stick to stable Rust.)
>
> I would expect we'd want a fairly tight coupling between kernel
> releases and minimum rust releases at first. Whatever is the latest
> stable rust version during the kernel's merge window might be
> assumed to be the minimum version for the life of that kernel, but
> an LTS release would not suddenly start relying on features
> from a newer compiler (thought it might warn about known bugs).
Agreed; we should be careful that any backported fix to an LTS kernel
does not increase the required Rust toolchain.
> While Linux used to build with 12 year old compilers (4.1 until
> 2018), we now require a 6 year old gcc (4.9) or 1 year old
> clang/llvm. I don't know whether these will fully converge over
> time but it seems sensible that the minimum rust frontend version
> we require for a new kernel release would eventually also fall
> in that range, requiring a compiler that is no more than a few
> years old, but not requiring the latest stable release.
I expect in the short term that we will likely have a need for features
from recent stable releases, especially when those features were added
specifically to support the kernel or similar, but the rate at which we
need new features will slow over time, and eventually we'll go from
"latest stable" to "within a year or so".
^ permalink raw reply
* Re: [PATCH v3 0/3] Off-load TLB invalidations to host for !GTSE
From: Stephen Rothwell @ 2020-07-16 23:09 UTC (permalink / raw)
To: Qian Cai
Cc: aneesh.kumar, linux-kernel, npiggin, Bharata B Rao, linux-next,
linuxppc-dev
In-Reply-To: <20200716172713.GA4565@lca.pw>
[-- Attachment #1: Type: text/plain, Size: 308 bytes --]
Hi all,
On Thu, 16 Jul 2020 13:27:14 -0400 Qian Cai <cai@lca.pw> wrote:
>
> Reverting the whole series fixed random memory corruptions during boot on
> POWER9 PowerNV systems below.
I will revert those commits from linux-next today as well (they revert
cleanly).
--
Cheers,
Stephen Rothwell
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH v8 2/5] remoteproc: qcom_q6v5_mss: Replace mask based tracking with size
From: Rishabh Bhatnagar @ 2020-07-16 22:20 UTC (permalink / raw)
To: linux-remoteproc, linux-kernel
Cc: bjorn.andersson, mathieu.poirier, sibis, tsoni, psodagud, sidgup,
Sibi Sankar, Rishabh Bhatnagar
In-Reply-To: <1594938035-7327-1-git-send-email-rishabhb@codeaurora.org>
From: Sibi Sankar <sibis@codeaurora.org>
In order to land inline coredump support for mss, the dump_segment
function would need to support granularities less than the segment
size. This is achieved by replacing mask based tracking with size.
Signed-off-by: Sibi Sankar <sibis@codeaurora.org>
Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>
---
drivers/remoteproc/qcom_q6v5_mss.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index feb70283b..037cd45 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -181,8 +181,8 @@ struct q6v5 {
bool running;
bool dump_mba_loaded;
- unsigned long dump_segment_mask;
- unsigned long dump_complete_mask;
+ size_t current_dump_size;
+ size_t total_dump_size;
phys_addr_t mba_phys;
void *mba_region;
@@ -1203,7 +1203,6 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc,
{
int ret = 0;
struct q6v5 *qproc = rproc->priv;
- unsigned long mask = BIT((unsigned long)segment->priv);
int offset = segment->da - qproc->mpss_reloc;
void *ptr = NULL;
@@ -1229,10 +1228,10 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc,
memset(dest, 0xff, segment->size);
}
- qproc->dump_segment_mask |= mask;
+ qproc->current_dump_size += segment->size;
/* Reclaim mba after copying segments */
- if (qproc->dump_segment_mask == qproc->dump_complete_mask) {
+ if (qproc->current_dump_size == qproc->total_dump_size) {
if (qproc->dump_mba_loaded) {
/* Try to reset ownership back to Q6 */
q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm,
@@ -1274,7 +1273,7 @@ static int q6v5_start(struct rproc *rproc)
"Failed to reclaim mba buffer system may become unstable\n");
/* Reset Dump Segment Mask */
- qproc->dump_segment_mask = 0;
+ qproc->current_dump_size = 0;
qproc->running = true;
return 0;
@@ -1323,7 +1322,7 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc,
ehdr = (struct elf32_hdr *)fw->data;
phdrs = (struct elf32_phdr *)(ehdr + 1);
- qproc->dump_complete_mask = 0;
+ qproc->total_dump_size = 0;
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
@@ -1334,11 +1333,11 @@ static int qcom_q6v5_register_dump_segments(struct rproc *rproc,
ret = rproc_coredump_add_custom_segment(rproc, phdr->p_paddr,
phdr->p_memsz,
qcom_q6v5_dump_segment,
- (void *)i);
+ NULL);
if (ret)
break;
- qproc->dump_complete_mask |= BIT(i);
+ qproc->total_dump_size += phdr->p_memsz;
}
release_firmware(fw);
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* [Intel-gfx] ✗ Fi.CI.IGT: failure for drm/i915: PCI ID cleanup
From: Patchwork @ 2020-07-16 23:11 UTC (permalink / raw)
To: Ville Syrjala; +Cc: intel-gfx
In-Reply-To: <20200716172106.2656-1-ville.syrjala@linux.intel.com>
[-- Attachment #1.1: Type: text/plain, Size: 15746 bytes --]
== Series Details ==
Series: drm/i915: PCI ID cleanup
URL : https://patchwork.freedesktop.org/series/79561/
State : failure
== Summary ==
CI Bug Log - changes from CI_DRM_8757_full -> Patchwork_18192_full
====================================================
Summary
-------
**FAILURE**
Serious unknown changes coming with Patchwork_18192_full absolutely need to be
verified manually.
If you think the reported changes have nothing to do with the changes
introduced in Patchwork_18192_full, please notify your bug team to allow them
to document this new failure mode, which will reduce false positives in CI.
Possible new issues
-------------------
Here are the unknown changes that may have been introduced in Patchwork_18192_full:
### IGT changes ###
#### Possible regressions ####
* igt@i915_suspend@sysfs-reader:
- shard-skl: [PASS][1] -> [INCOMPLETE][2]
[1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl2/igt@i915_suspend@sysfs-reader.html
[2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl10/igt@i915_suspend@sysfs-reader.html
Known issues
------------
Here are the changes found in Patchwork_18192_full that come from known issues:
### IGT changes ###
#### Issues hit ####
* igt@gem_exec_balancer@bonded-early:
- shard-kbl: [PASS][3] -> [FAIL][4] ([i915#2079])
[3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-kbl3/igt@gem_exec_balancer@bonded-early.html
[4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-kbl2/igt@gem_exec_balancer@bonded-early.html
* igt@kms_big_fb@x-tiled-64bpp-rotate-0:
- shard-glk: [PASS][5] -> [DMESG-FAIL][6] ([i915#118] / [i915#95]) +1 similar issue
[5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-glk2/igt@kms_big_fb@x-tiled-64bpp-rotate-0.html
[6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-glk8/igt@kms_big_fb@x-tiled-64bpp-rotate-0.html
* igt@kms_cursor_crc@pipe-c-cursor-suspend:
- shard-kbl: [PASS][7] -> [DMESG-WARN][8] ([i915#180]) +8 similar issues
[7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-kbl6/igt@kms_cursor_crc@pipe-c-cursor-suspend.html
[8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-kbl4/igt@kms_cursor_crc@pipe-c-cursor-suspend.html
* igt@kms_draw_crc@draw-method-xrgb2101010-mmap-wc-untiled:
- shard-apl: [PASS][9] -> [DMESG-WARN][10] ([i915#1635] / [i915#1982])
[9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-apl8/igt@kms_draw_crc@draw-method-xrgb2101010-mmap-wc-untiled.html
[10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-apl2/igt@kms_draw_crc@draw-method-xrgb2101010-mmap-wc-untiled.html
* igt@kms_flip@2x-flip-vs-expired-vblank@ab-hdmi-a1-hdmi-a2:
- shard-glk: [PASS][11] -> [FAIL][12] ([i915#79]) +1 similar issue
[11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-glk7/igt@kms_flip@2x-flip-vs-expired-vblank@ab-hdmi-a1-hdmi-a2.html
[12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-glk4/igt@kms_flip@2x-flip-vs-expired-vblank@ab-hdmi-a1-hdmi-a2.html
* igt@kms_flip@plain-flip-fb-recreate@b-edp1:
- shard-skl: [PASS][13] -> [FAIL][14] ([i915#2122])
[13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl4/igt@kms_flip@plain-flip-fb-recreate@b-edp1.html
[14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl3/igt@kms_flip@plain-flip-fb-recreate@b-edp1.html
* igt@kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-move:
- shard-tglb: [PASS][15] -> [DMESG-WARN][16] ([i915#1982]) +1 similar issue
[15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-tglb1/igt@kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-move.html
[16]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-tglb2/igt@kms_frontbuffer_tracking@psr-1p-primscrn-spr-indfb-move.html
* igt@kms_frontbuffer_tracking@psr-suspend:
- shard-skl: [PASS][17] -> [INCOMPLETE][18] ([i915#123])
[17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl6/igt@kms_frontbuffer_tracking@psr-suspend.html
[18]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl4/igt@kms_frontbuffer_tracking@psr-suspend.html
* igt@kms_plane_alpha_blend@pipe-c-coverage-7efc:
- shard-skl: [PASS][19] -> [FAIL][20] ([fdo#108145] / [i915#265]) +1 similar issue
[19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl10/igt@kms_plane_alpha_blend@pipe-c-coverage-7efc.html
[20]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl8/igt@kms_plane_alpha_blend@pipe-c-coverage-7efc.html
* igt@kms_psr2_su@frontbuffer:
- shard-iclb: [PASS][21] -> [SKIP][22] ([fdo#109642] / [fdo#111068])
[21]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-iclb2/igt@kms_psr2_su@frontbuffer.html
[22]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-iclb5/igt@kms_psr2_su@frontbuffer.html
* igt@kms_psr@psr2_cursor_mmap_cpu:
- shard-iclb: [PASS][23] -> [SKIP][24] ([fdo#109441]) +2 similar issues
[23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-iclb2/igt@kms_psr@psr2_cursor_mmap_cpu.html
[24]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-iclb7/igt@kms_psr@psr2_cursor_mmap_cpu.html
* igt@kms_vblank@crtc-id:
- shard-skl: [PASS][25] -> [DMESG-WARN][26] ([i915#1982]) +4 similar issues
[25]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl3/igt@kms_vblank@crtc-id.html
[26]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl9/igt@kms_vblank@crtc-id.html
* igt@perf@polling-parameterized:
- shard-tglb: [PASS][27] -> [FAIL][28] ([i915#1542])
[27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-tglb5/igt@perf@polling-parameterized.html
[28]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-tglb7/igt@perf@polling-parameterized.html
* igt@perf@polling-small-buf:
- shard-skl: [PASS][29] -> [FAIL][30] ([i915#1722])
[29]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl5/igt@perf@polling-small-buf.html
[30]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl1/igt@perf@polling-small-buf.html
* igt@perf_pmu@semaphore-busy@rcs0:
- shard-kbl: [PASS][31] -> [FAIL][32] ([i915#1820])
[31]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-kbl7/igt@perf_pmu@semaphore-busy@rcs0.html
[32]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-kbl2/igt@perf_pmu@semaphore-busy@rcs0.html
* igt@vgem_slow@nohang:
- shard-tglb: [PASS][33] -> [DMESG-WARN][34] ([i915#402])
[33]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-tglb6/igt@vgem_slow@nohang.html
[34]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-tglb1/igt@vgem_slow@nohang.html
#### Possible fixes ####
* igt@gem_ctx_persistence@processes:
- shard-skl: [FAIL][35] ([i915#1528]) -> [PASS][36]
[35]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl1/igt@gem_ctx_persistence@processes.html
[36]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl4/igt@gem_ctx_persistence@processes.html
* igt@gem_userptr_blits@invalid-mmap-offset-unsync@gtt:
- shard-tglb: [INCOMPLETE][37] ([i915#2119] / [i915#2149]) -> [PASS][38]
[37]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-tglb7/igt@gem_userptr_blits@invalid-mmap-offset-unsync@gtt.html
[38]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-tglb6/igt@gem_userptr_blits@invalid-mmap-offset-unsync@gtt.html
* igt@gem_workarounds@suspend-resume-fd:
- shard-skl: [INCOMPLETE][39] -> [PASS][40]
[39]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl10/igt@gem_workarounds@suspend-resume-fd.html
[40]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl2/igt@gem_workarounds@suspend-resume-fd.html
* igt@i915_module_load@reload:
- shard-tglb: [DMESG-WARN][41] ([i915#402]) -> [PASS][42]
[41]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-tglb6/igt@i915_module_load@reload.html
[42]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-tglb7/igt@i915_module_load@reload.html
* igt@kms_color@pipe-c-ctm-0-25:
- shard-skl: [DMESG-WARN][43] ([i915#1982]) -> [PASS][44] +3 similar issues
[43]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl1/igt@kms_color@pipe-c-ctm-0-25.html
[44]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl3/igt@kms_color@pipe-c-ctm-0-25.html
* igt@kms_cursor_crc@pipe-b-cursor-64x64-onscreen:
- shard-skl: [FAIL][45] ([i915#54]) -> [PASS][46]
[45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl1/igt@kms_cursor_crc@pipe-b-cursor-64x64-onscreen.html
[46]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl3/igt@kms_cursor_crc@pipe-b-cursor-64x64-onscreen.html
* igt@kms_flip@flip-vs-expired-vblank@a-edp1:
- shard-skl: [FAIL][47] ([i915#79]) -> [PASS][48] +1 similar issue
[47]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl8/igt@kms_flip@flip-vs-expired-vblank@a-edp1.html
[48]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl1/igt@kms_flip@flip-vs-expired-vblank@a-edp1.html
* igt@kms_flip@flip-vs-suspend-interruptible@c-edp1:
- shard-skl: [INCOMPLETE][49] ([i915#198]) -> [PASS][50]
[49]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl9/igt@kms_flip@flip-vs-suspend-interruptible@c-edp1.html
[50]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl8/igt@kms_flip@flip-vs-suspend-interruptible@c-edp1.html
* igt@kms_flip_tiling@flip-changes-tiling-yf:
- shard-kbl: [DMESG-WARN][51] ([i915#1982]) -> [PASS][52]
[51]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-kbl6/igt@kms_flip_tiling@flip-changes-tiling-yf.html
[52]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-kbl4/igt@kms_flip_tiling@flip-changes-tiling-yf.html
* igt@kms_frontbuffer_tracking@fbc-suspend:
- shard-kbl: [DMESG-WARN][53] ([i915#180]) -> [PASS][54] +7 similar issues
[53]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-kbl4/igt@kms_frontbuffer_tracking@fbc-suspend.html
[54]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-kbl3/igt@kms_frontbuffer_tracking@fbc-suspend.html
* igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-pwrite:
- shard-tglb: [DMESG-WARN][55] ([i915#1982]) -> [PASS][56] +1 similar issue
[55]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-tglb2/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-pwrite.html
[56]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-tglb3/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-pwrite.html
* igt@kms_plane_alpha_blend@pipe-b-constant-alpha-min:
- shard-skl: [FAIL][57] ([fdo#108145] / [i915#265]) -> [PASS][58]
[57]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-skl2/igt@kms_plane_alpha_blend@pipe-b-constant-alpha-min.html
[58]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-skl9/igt@kms_plane_alpha_blend@pipe-b-constant-alpha-min.html
* igt@kms_psr@psr2_basic:
- shard-iclb: [SKIP][59] ([fdo#109441]) -> [PASS][60]
[59]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-iclb8/igt@kms_psr@psr2_basic.html
[60]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-iclb2/igt@kms_psr@psr2_basic.html
* igt@kms_vblank@pipe-c-wait-busy-hang:
- shard-apl: [DMESG-WARN][61] ([i915#1635] / [i915#1982]) -> [PASS][62]
[61]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-apl1/igt@kms_vblank@pipe-c-wait-busy-hang.html
[62]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-apl4/igt@kms_vblank@pipe-c-wait-busy-hang.html
#### Warnings ####
* igt@kms_plane_alpha_blend@pipe-a-alpha-7efc:
- shard-apl: [DMESG-FAIL][63] ([fdo#108145] / [i915#1635] / [i915#1982]) -> [FAIL][64] ([fdo#108145] / [i915#1635] / [i915#265])
[63]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-apl6/igt@kms_plane_alpha_blend@pipe-a-alpha-7efc.html
[64]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-apl7/igt@kms_plane_alpha_blend@pipe-a-alpha-7efc.html
* igt@runner@aborted:
- shard-apl: ([FAIL][65], [FAIL][66], [FAIL][67], [FAIL][68]) ([i915#1610] / [i915#1635] / [i915#2110]) -> [FAIL][69] ([i915#1635] / [i915#2110])
[65]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-apl1/igt@runner@aborted.html
[66]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-apl8/igt@runner@aborted.html
[67]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-apl3/igt@runner@aborted.html
[68]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_8757/shard-apl7/igt@runner@aborted.html
[69]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/shard-apl2/igt@runner@aborted.html
[fdo#108145]: https://bugs.freedesktop.org/show_bug.cgi?id=108145
[fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
[fdo#109642]: https://bugs.freedesktop.org/show_bug.cgi?id=109642
[fdo#111068]: https://bugs.freedesktop.org/show_bug.cgi?id=111068
[i915#118]: https://gitlab.freedesktop.org/drm/intel/issues/118
[i915#123]: https://gitlab.freedesktop.org/drm/intel/issues/123
[i915#1528]: https://gitlab.freedesktop.org/drm/intel/issues/1528
[i915#1542]: https://gitlab.freedesktop.org/drm/intel/issues/1542
[i915#1610]: https://gitlab.freedesktop.org/drm/intel/issues/1610
[i915#1635]: https://gitlab.freedesktop.org/drm/intel/issues/1635
[i915#1722]: https://gitlab.freedesktop.org/drm/intel/issues/1722
[i915#180]: https://gitlab.freedesktop.org/drm/intel/issues/180
[i915#1820]: https://gitlab.freedesktop.org/drm/intel/issues/1820
[i915#198]: https://gitlab.freedesktop.org/drm/intel/issues/198
[i915#1982]: https://gitlab.freedesktop.org/drm/intel/issues/1982
[i915#2079]: https://gitlab.freedesktop.org/drm/intel/issues/2079
[i915#2110]: https://gitlab.freedesktop.org/drm/intel/issues/2110
[i915#2119]: https://gitlab.freedesktop.org/drm/intel/issues/2119
[i915#2122]: https://gitlab.freedesktop.org/drm/intel/issues/2122
[i915#2149]: https://gitlab.freedesktop.org/drm/intel/issues/2149
[i915#265]: https://gitlab.freedesktop.org/drm/intel/issues/265
[i915#402]: https://gitlab.freedesktop.org/drm/intel/issues/402
[i915#54]: https://gitlab.freedesktop.org/drm/intel/issues/54
[i915#79]: https://gitlab.freedesktop.org/drm/intel/issues/79
[i915#95]: https://gitlab.freedesktop.org/drm/intel/issues/95
Participating hosts (10 -> 10)
------------------------------
No changes in participating hosts
Build changes
-------------
* Linux: CI_DRM_8757 -> Patchwork_18192
CI-20190529: 20190529
CI_DRM_8757: 6802049b80a49f5f45c2bc2dd3e6d189204dc2bb @ git://anongit.freedesktop.org/gfx-ci/linux
IGT_5738: bc8b56fe177af34fbde7b96f1f66614a0014c6ef @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
Patchwork_18192: e65cc9c4b7954706e66eaef7e8d093304a181512 @ git://anongit.freedesktop.org/gfx-ci/linux
piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit
== Logs ==
For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18192/index.html
[-- Attachment #1.2: Type: text/html, Size: 18618 bytes --]
[-- Attachment #2: Type: text/plain, Size: 160 bytes --]
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH] iommu/arm-smmu-v3: remove the approach of MSI polling for CMD SYNC
From: Barry Song @ 2020-07-16 23:07 UTC (permalink / raw)
To: robin.murphy, will, joro
Cc: Barry Song, linux-kernel, linuxarm, iommu, Prime Zeng,
linux-arm-kernel
Before commit 587e6c10a7ce ("iommu/arm-smmu-v3: Reduce contention during
command-queue insertion"), msi polling perhaps performed better since
it could run outside the spin_lock_irqsave() while the code polling cons
reg was running in the lock.
But after the great reorganization of smmu queue, neither of these two
polling methods are running in a spinlock. And real tests show polling
cons reg via sev means smaller latency. It is probably because polling
by msi will ask hardware to write memory but sev polling depends on the
update of register only.
Using 16 threads to run netperf on hns3 100G NIC with UDP packet size
in 32768bytes and set iommu to strict, TX throughput can improve from
25227.74Mbps to 27145.59Mbps by this patch. In this case, SMMU is super
busy as hns3 sends map/unmap requests extremely frequently.
Cc: Prime Zeng <prime.zeng@hisilicon.com>
Signed-off-by: Barry Song <song.bao.hua@hisilicon.com>
---
drivers/iommu/arm-smmu-v3.c | 46 +------------------------------------
1 file changed, 1 insertion(+), 45 deletions(-)
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index f578677a5c41..e55282a636c8 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -964,12 +964,7 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
cmd[1] |= FIELD_PREP(CMDQ_PRI_1_RESP, ent->pri.resp);
break;
case CMDQ_OP_CMD_SYNC:
- if (ent->sync.msiaddr) {
- cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_IRQ);
- cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK;
- } else {
- cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV);
- }
+ cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV);
cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH);
cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB);
break;
@@ -983,21 +978,10 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,
u32 prod)
{
- struct arm_smmu_queue *q = &smmu->cmdq.q;
struct arm_smmu_cmdq_ent ent = {
.opcode = CMDQ_OP_CMD_SYNC,
};
- /*
- * Beware that Hi16xx adds an extra 32 bits of goodness to its MSI
- * payload, so the write will zero the entire command on that platform.
- */
- if (smmu->features & ARM_SMMU_FEAT_MSI &&
- smmu->features & ARM_SMMU_FEAT_COHERENCY) {
- ent.sync.msiaddr = q->base_dma + Q_IDX(&q->llq, prod) *
- q->ent_dwords * 8;
- }
-
arm_smmu_cmdq_build_cmd(cmd, &ent);
}
@@ -1251,30 +1235,6 @@ static int arm_smmu_cmdq_poll_until_not_full(struct arm_smmu_device *smmu,
return ret;
}
-/*
- * Wait until the SMMU signals a CMD_SYNC completion MSI.
- * Must be called with the cmdq lock held in some capacity.
- */
-static int __arm_smmu_cmdq_poll_until_msi(struct arm_smmu_device *smmu,
- struct arm_smmu_ll_queue *llq)
-{
- int ret = 0;
- struct arm_smmu_queue_poll qp;
- struct arm_smmu_cmdq *cmdq = &smmu->cmdq;
- u32 *cmd = (u32 *)(Q_ENT(&cmdq->q, llq->prod));
-
- queue_poll_init(smmu, &qp);
-
- /*
- * The MSI won't generate an event, since it's being written back
- * into the command queue.
- */
- qp.wfe = false;
- smp_cond_load_relaxed(cmd, !VAL || (ret = queue_poll(&qp)));
- llq->cons = ret ? llq->prod : queue_inc_prod_n(llq, 1);
- return ret;
-}
-
/*
* Wait until the SMMU cons index passes llq->prod.
* Must be called with the cmdq lock held in some capacity.
@@ -1332,10 +1292,6 @@ static int __arm_smmu_cmdq_poll_until_consumed(struct arm_smmu_device *smmu,
static int arm_smmu_cmdq_poll_until_sync(struct arm_smmu_device *smmu,
struct arm_smmu_ll_queue *llq)
{
- if (smmu->features & ARM_SMMU_FEAT_MSI &&
- smmu->features & ARM_SMMU_FEAT_COHERENCY)
- return __arm_smmu_cmdq_poll_until_msi(smmu, llq);
-
return __arm_smmu_cmdq_poll_until_consumed(smmu, llq);
}
--
2.27.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH] configfs: Use flush file op to commit writes to a binary file
From: Lenny Szubowicz @ 2020-07-16 22:55 UTC (permalink / raw)
To: linux-kernel, jlbec, hch; +Cc: rjw
Use the flush file operation instead of the release operation to commit
the prior writes to a configfs binary file. This allows any error
status from the commit to be returned as the status of the close.
Both flush and release are invoked during a close, but the status from
release is ignored by the file system layer because the release operation
is not supposed to fail.
For example, prior to this change no error is returned to user space
when acpi_configfs correctly fails a write that attempts to commit an
ACPI aml configfs binary file when kernel lockdown is in effect.
This patch allows an error status to get returned to user space instead
of a misleading success status.
Note that during a close, release is only called on the last reference to
the specified file struct whereas flush is called on every close.
Therefore, to preserve the prior behavior, configfs_flush_bin_file()
doesn't commit the prior writes if there are still multiple references.
Additionally, since configfs does not support the fsync file operation,
a configfs flush only occurs in the context of a close. This makes it
safe to move the commit from release to flush.
Signed-off-by: Lenny Szubowicz <lszubowi@redhat.com>
---
fs/configfs/file.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index fb65b706cc0d..df0a76f7e62b 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -466,9 +466,28 @@ static int configfs_open_bin_file(struct inode *inode, struct file *filp)
return __configfs_open_file(inode, filp, CONFIGFS_ITEM_BIN_ATTR);
}
-static int configfs_release_bin_file(struct inode *inode, struct file *file)
+/**
+ * configfs_flush_bin_file - flush a binary attribute.
+ * @file: file pointer
+ * @id: pointer to files_struct
+ *
+ * Flush is called during close and commits the buffered binary
+ * writes when there are no more shared references to this file
+ * struct.
+ *
+ * Any error returned from the flush will be reflected in the
+ * return value from the close.
+ */
+
+static int configfs_flush_bin_file(struct file *file, fl_owner_t id)
{
struct configfs_buffer *buffer = file->private_data;
+ ssize_t len;
+ int ret = 0;
+
+ /* Only commit the data if no more shared refs to file */
+ if (file_count(file) > 1)
+ return 0;
buffer->read_in_progress = false;
@@ -478,10 +497,11 @@ static int configfs_release_bin_file(struct inode *inode, struct file *file)
down_read(&frag->frag_sem);
if (!frag->frag_dead) {
- /* result of ->release() is ignored */
- buffer->bin_attr->write(buffer->item,
+ len = buffer->bin_attr->write(buffer->item,
buffer->bin_buffer,
buffer->bin_buffer_size);
+ if (len < 0)
+ ret = len;
}
up_read(&frag->frag_sem);
/* vfree on NULL is safe */
@@ -491,8 +511,7 @@ static int configfs_release_bin_file(struct inode *inode, struct file *file)
buffer->needs_read_fill = 1;
}
- configfs_release(inode, file);
- return 0;
+ return ret;
}
@@ -509,7 +528,8 @@ const struct file_operations configfs_bin_file_operations = {
.write = configfs_write_bin_file,
.llseek = NULL, /* bin file is not seekable */
.open = configfs_open_bin_file,
- .release = configfs_release_bin_file,
+ .flush = configfs_flush_bin_file,
+ .release = configfs_release,
};
/**
--
2.27.0
^ permalink raw reply related
* [PATCH] [PATCH] Firmware security information in SYSFS
From: Daniel Gutson @ 2020-07-16 22:36 UTC (permalink / raw)
To: Daniel Gutson, Derek Kiernan, Tudor Ambarus, Miquel Raynal,
Richard Weinberger, Vignesh Raghavendra, Mika Westerberg,
Arnd Bergmann, Greg Kroah-Hartman, Mauro Carvalho Chehab,
linux-kernel, Richard Hughes, Alex Bazhaniuk
This patch exports security-related firmware configuration
in the sysfs filesystem. In this initial patch, I include
some configuration attributes for the system SPI chip.
This initial version exports the BIOS Write Enable (bioswe),
BIOS Lock Enable (ble), and the SMM Bios Write Protect (SMM_BWP)
fields of the Bios Control register. The idea is to keep adding more
flags, not only from the BC but also from other registers in following
versions.
The goal is that the attributes are avilable to fwupd when SecureBoot
is turned on.
The patch provides a new misc driver, as proposed in the previous patch,
that provides registration functions for HW Driver devices.
In this case, the intel SPI flash chip (intel-spi) registers functions
so it can export the three attributes mentioned above.
Signed-off-by: Daniel Gutson <daniel.gutson@eclypsium.com>
---
.../ABI/stable/sysfs-firmware-security | 23 ++++
MAINTAINERS | 7 ++
drivers/misc/Kconfig | 9 ++
drivers/misc/Makefile | 1 +
drivers/misc/firmware_security_data.c | 103 ++++++++++++++++++
drivers/mtd/spi-nor/controllers/Kconfig | 1 +
.../mtd/spi-nor/controllers/intel-spi-pci.c | 45 +++++++-
drivers/mtd/spi-nor/controllers/intel-spi.c | 92 ++++++++++++----
.../platform_data/firmware_security_data.h | 17 +++
9 files changed, 277 insertions(+), 21 deletions(-)
create mode 100644 Documentation/ABI/stable/sysfs-firmware-security
create mode 100644 drivers/misc/firmware_security_data.c
create mode 100644 include/linux/platform_data/firmware_security_data.h
diff --git a/Documentation/ABI/stable/sysfs-firmware-security b/Documentation/ABI/stable/sysfs-firmware-security
new file mode 100644
index 000000000000..fdfcc40c3c09
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-firmware-security
@@ -0,0 +1,23 @@
+What: /sys/kernel/firmware-security/bioswe
+Date: July 2020
+KernelVersion: 5.8.0
+Contact: Daniel Gutson <daniel.gutson@eclypsium.com>
+Description: If the system firmware set BIOS Write Enable.
+ 0: writes disabled, 1: writes enabled.
+Users: https://github.com/fwupd/fwupd
+
+What: /sys/kernel/firmware-security/ble
+Date: July 2020
+KernelVersion: 5.8.0
+Contact: Daniel Gutson <daniel.gutson@eclypsium.com>
+Description: If the system firmware set Bios Lock Enable.
+ 0: SMM lock disabled, 1: SMM lock enabled.
+Users: https://github.com/fwupd/fwupd
+
+What: /sys/kernel/firmware-security/smm_bwp
+Date: July 2020
+KernelVersion: 5.8.0
+Contact: Daniel Gutson <daniel.gutson@eclypsium.com>
+Description: If the system firmware set SMM Bios Write Protect.
+ 0: writes disabled unless in SMM, 1: writes enabled.
+Users: https://github.com/fwupd/fwupd
diff --git a/MAINTAINERS b/MAINTAINERS
index b4a43a9e7fbc..152b3b9b802c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6699,6 +6699,13 @@ F: Documentation/firmware_class/
F: drivers/base/firmware_loader/
F: include/linux/firmware.h
+FIRMWARE SECURITY DATA
+M: Daniel Gutson <daniel.gutson@eclypsium.com>
+S: Supported
+F: Documentation/ABI/sysfs-firmware-security
+F: drivers/misc/firmware_security_data.c
+F: include/linux/platform_data/firmware_security_data.h
+
FLASH ADAPTER DRIVER (IBM Flash Adapter 900GB Full Height PCI Flash Card)
M: Joshua Morris <josh.h.morris@us.ibm.com>
M: Philip Kelleher <pjk1939@linux.ibm.com>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index e1b1ba5e2b92..72fafb63be58 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -456,6 +456,15 @@ config PVPANIC
a paravirtualized device provided by QEMU; it lets a virtual machine
(guest) communicate panic events to the host.
+config FIRMWARE_SECURITY_DATA
+ tristate "Firmware security information in the SYSFS"
+ depends on SYSFS
+ help
+ This kernel module is a helper driver to provide information about
+ firmware security settings and configuration.
+ This module is used by other device drivers -such as the intel-spi-
+ to publish the information in /sys/kernel/firmware_security.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c7bd01ac6291..f938abc2f733 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_HABANA_AI) += habanalabs/
obj-$(CONFIG_UACCE) += uacce/
obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
+obj-$(CONFIG_FIRMWARE_SECURITY_DATA) += firmware_security_data.o
diff --git a/drivers/misc/firmware_security_data.c b/drivers/misc/firmware_security_data.c
new file mode 100644
index 000000000000..cfb7f39a2cd9
--- /dev/null
+++ b/drivers/misc/firmware_security_data.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Firmware security data kernel module
+ *
+ * Copyright (C) 2020 Daniel Gutson <daniel.gutson@eclypsium.com>
+ * Copyright (C) 2020 Eclypsium Inc.
+ */
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/platform_data/firmware_security_data.h>
+
+static DEFINE_MUTEX(entries_mutex);
+static LIST_HEAD(entries);
+static struct kobject *firmware_data_kobj;
+
+struct firmware_security_data {
+ struct kobj_attribute kobj_attr;
+ ssize_t (*callback)(char *buf, void *private_data);
+ void *private_data;
+ struct list_head list_node;
+};
+
+static ssize_t internal_callback(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct firmware_security_data *fwsd =
+ container_of(attr, struct firmware_security_data, kobj_attr);
+ return fwsd->callback(buf, fwsd->private_data);
+}
+
+int register_firmware_security_data_callback(
+ const char *name, ssize_t (*callback)(char *buf, void *private_data),
+ void *private_data)
+{
+ int retval;
+
+ struct firmware_security_data *new_data;
+
+ if (name == NULL || name[0] == 0)
+ return -EINVAL;
+
+ new_data = kmalloc(sizeof(struct firmware_security_data), GFP_KERNEL);
+ if (new_data == NULL)
+ return -ENOMEM;
+
+ /* initialize attributes: */
+ sysfs_attr_init(new_data->kobj_attr.attr);
+ new_data->kobj_attr.attr.name = name;
+ new_data->kobj_attr.attr.mode = 0664;
+ new_data->kobj_attr.show = internal_callback;
+ new_data->kobj_attr.store = NULL;
+
+ new_data->callback = callback;
+ new_data->private_data = private_data;
+
+ /* attempt to create the file: */
+ retval = sysfs_create_file(firmware_data_kobj,
+ &new_data->kobj_attr.attr);
+ if (retval == 0) {
+ /* append to the list of entries: */
+ INIT_LIST_HEAD(&new_data->list_node);
+ mutex_lock(&entries_mutex);
+ list_add(&new_data->list_node, &entries);
+ mutex_unlock(&entries_mutex);
+ } else {
+ kfree(new_data);
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(register_firmware_security_data_callback);
+
+static int __init firmware_security_data_init(void)
+{
+ firmware_data_kobj =
+ kobject_create_and_add("firmware_security", kernel_kobj);
+ if (!firmware_data_kobj)
+ return -ENOMEM;
+
+ return 0;
+}
+static void __exit firmware_security_data_exit(void)
+{
+ struct list_head *entry = entries.next;
+
+ while (entry != &entries) {
+ struct list_head *next = entry->next;
+
+ kfree(list_entry(entry, struct firmware_security_data,
+ list_node));
+ entry = next;
+ }
+
+ kobject_put(firmware_data_kobj);
+}
+module_init(firmware_security_data_init);
+module_exit(firmware_security_data_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Daniel Gutson <daniel.gutson@eclypsium.com>");
diff --git a/drivers/mtd/spi-nor/controllers/Kconfig b/drivers/mtd/spi-nor/controllers/Kconfig
index d89a5ea9446a..01d9c49f8e49 100644
--- a/drivers/mtd/spi-nor/controllers/Kconfig
+++ b/drivers/mtd/spi-nor/controllers/Kconfig
@@ -45,6 +45,7 @@ config SPI_INTEL_SPI_PCI
tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)"
depends on X86 && PCI
select SPI_INTEL_SPI
+ select FIRMWARE_SECURITY_DATA
help
This enables PCI support for the Intel PCH/PCU SPI controller in
master mode. This controller is present in modern Intel hardware
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
index 81329f680bec..f919f09de1e4 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
+++ b/drivers/mtd/spi-nor/controllers/intel-spi-pci.c
@@ -10,11 +10,14 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/platform_data/firmware_security_data.h>
#include "intel-spi.h"
#define BCR 0xdc
#define BCR_WPD BIT(0)
+#define BCR_BLE BIT(1)
+#define BCR_SMM_BWP BIT(5)
static const struct intel_spi_boardinfo bxt_info = {
.type = INTEL_SPI_BXT,
@@ -24,6 +27,44 @@ static const struct intel_spi_boardinfo cnl_info = {
.type = INTEL_SPI_CNL,
};
+static ssize_t cnl_read_field(char *buf, struct pci_dev *pdev, u32 mask)
+{
+ u32 bcr;
+
+ if (pci_read_config_dword(pdev, BCR, &bcr) != PCIBIOS_SUCCESSFUL)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", (int)!!(bcr & mask));
+}
+
+static ssize_t cnl_wpd_firmware_security_callbacks(char *buf,
+ void *private_data)
+{
+ return cnl_read_field(buf, (struct pci_dev *)private_data, BCR_WPD);
+}
+
+static ssize_t cnl_ble_firmware_security_callbacks(char *buf,
+ void *private_data)
+{
+ return cnl_read_field(buf, (struct pci_dev *)private_data, BCR_BLE);
+}
+
+static ssize_t cnl_smm_bwp_firmware_security_callbacks(char *buf,
+ void *private_data)
+{
+ return cnl_read_field(buf, (struct pci_dev *)private_data, BCR_SMM_BWP);
+}
+
+static void register_firmware_security_data_callbacks(struct pci_dev *pdev)
+{
+ register_firmware_security_data_callback(
+ "bioswe", &cnl_wpd_firmware_security_callbacks, pdev);
+ register_firmware_security_data_callback(
+ "ble", &cnl_ble_firmware_security_callbacks, pdev);
+ register_firmware_security_data_callback(
+ "smm_bwp", &cnl_smm_bwp_firmware_security_callbacks, pdev);
+}
+
static int intel_spi_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -50,6 +91,8 @@ static int intel_spi_pci_probe(struct pci_dev *pdev,
}
info->writeable = !!(bcr & BCR_WPD);
+ register_firmware_security_data_callbacks(pdev);
+
ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info);
if (IS_ERR(ispi))
return PTR_ERR(ispi);
@@ -76,7 +119,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info },
- { },
+ {},
};
MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
diff --git a/drivers/mtd/spi-nor/controllers/intel-spi.c b/drivers/mtd/spi-nor/controllers/intel-spi.c
index 61d2a0ad2131..939259541e75 100644
--- a/drivers/mtd/spi-nor/controllers/intel-spi.c
+++ b/drivers/mtd/spi-nor/controllers/intel-spi.c
@@ -16,6 +16,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/spi-nor.h>
#include <linux/platform_data/intel-spi.h>
+#include <linux/platform_data/firmware_security_data.h>
#include "intel-spi.h"
@@ -48,17 +49,17 @@
#define FADDR 0x08
#define DLOCK 0x0c
-#define FDATA(n) (0x10 + ((n) * 4))
+#define FDATA(n) (0x10 + ((n)*4))
#define FRACC 0x50
-#define FREG(n) (0x54 + ((n) * 4))
+#define FREG(n) (0x54 + ((n)*4))
#define FREG_BASE_MASK 0x3fff
#define FREG_LIMIT_SHIFT 16
#define FREG_LIMIT_MASK (0x03fff << FREG_LIMIT_SHIFT)
/* Offset is from @ispi->pregs */
-#define PR(n) ((n) * 4)
+#define PR(n) ((n)*4)
#define PR_WPE BIT(31)
#define PR_LIMIT_SHIFT 16
#define PR_LIMIT_MASK (0x3fff << PR_LIMIT_SHIFT)
@@ -95,6 +96,8 @@
#define BYT_SSFSTS_CTL 0x90
#define BYT_BCR 0xfc
#define BYT_BCR_WPD BIT(0)
+#define BYT_BCR_BLE BIT(1)
+#define BYT_BCR_SMM_BWP BIT(5)
#define BYT_FREG_NUM 5
#define BYT_PR_NUM 5
@@ -161,7 +164,8 @@ struct intel_spi {
static bool writeable;
module_param(writeable, bool, 0);
-MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)");
+MODULE_PARM_DESC(writeable,
+ "Enable write access to SPI flash chip (default=0)");
static void intel_spi_dump_regs(struct intel_spi *ispi)
{
@@ -179,8 +183,8 @@ static void intel_spi_dump_regs(struct intel_spi *ispi)
dev_dbg(ispi->dev, "DLOCK=0x%08x\n", readl(ispi->base + DLOCK));
for (i = 0; i < 16; i++)
- dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n",
- i, readl(ispi->base + FDATA(i)));
+ dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n", i,
+ readl(ispi->base + FDATA(i)));
dev_dbg(ispi->dev, "FRACC=0x%08x\n", readl(ispi->base + FRACC));
@@ -220,9 +224,8 @@ static void intel_spi_dump_regs(struct intel_spi *ispi)
base = value & PR_BASE_MASK;
dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x [%c%c]\n",
- i, base << 12, (limit << 12) | 0xfff,
- value & PR_WPE ? 'W' : '.',
- value & PR_RPE ? 'R' : '.');
+ i, base << 12, (limit << 12) | 0xfff,
+ value & PR_WPE ? 'W' : '.', value & PR_RPE ? 'R' : '.');
}
dev_dbg(ispi->dev, "Flash regions:\n");
@@ -237,7 +240,7 @@ static void intel_spi_dump_regs(struct intel_spi *ispi)
dev_dbg(ispi->dev, " %02d disabled\n", i);
else
dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x\n",
- i, base << 12, (limit << 12) | 0xfff);
+ i, base << 12, (limit << 12) | 0xfff);
}
dev_dbg(ispi->dev, "Using %cW sequencer for register access\n",
@@ -305,6 +308,52 @@ static int intel_spi_wait_sw_busy(struct intel_spi *ispi)
INTEL_SPI_TIMEOUT * 1000);
}
+static ssize_t byt_read_field(char *buf, const struct intel_spi *ispi, u32 mask)
+{
+ u32 val;
+
+ val = readl(ispi->base + BYT_BCR);
+ return sprintf(buf, "%d\n", (int)!!(val & mask));
+}
+
+static ssize_t byt_wpd_firmware_security_callbacks(char *buf,
+ void *private_data)
+{
+ return byt_read_field(buf, (struct intel_spi *)private_data,
+ BYT_BCR_WPD);
+}
+
+static ssize_t byt_ble_firmware_security_callbacks(char *buf,
+ void *private_data)
+{
+ return byt_read_field(buf, (struct intel_spi *)private_data,
+ BYT_BCR_BLE);
+}
+
+static ssize_t byt_smm_bwp_firmware_security_callbacks(char *buf,
+ void *private_data)
+{
+ return byt_read_field(buf, (struct intel_spi *)private_data,
+ BYT_BCR_SMM_BWP);
+}
+
+static void register_firmware_security_data_callbacks(struct intel_spi *ispi)
+{
+ switch (ispi->info->type) {
+ case INTEL_SPI_BYT:
+ register_firmware_security_data_callback(
+ "bioswe", &byt_wpd_firmware_security_callbacks, ispi);
+ register_firmware_security_data_callback(
+ "ble", &byt_ble_firmware_security_callbacks, ispi);
+ register_firmware_security_data_callback(
+ "smm_bwp", &byt_smm_bwp_firmware_security_callbacks,
+ ispi);
+ break;
+ default:
+ break; /* TODO. not yet implemented. */
+ }
+}
+
static int intel_spi_init(struct intel_spi *ispi)
{
u32 opmenu0, opmenu1, lvscc, uvscc, val;
@@ -383,7 +432,8 @@ static int intel_spi_init(struct intel_spi *ispi)
ispi->erase_64k = false;
if (ispi->sregs == NULL && (ispi->swseq_reg || ispi->swseq_erase)) {
- dev_err(ispi->dev, "software sequencer not supported, but required\n");
+ dev_err(ispi->dev,
+ "software sequencer not supported, but required\n");
return -EINVAL;
}
@@ -422,6 +472,8 @@ static int intel_spi_init(struct intel_spi *ispi)
intel_spi_dump_regs(ispi);
+ register_firmware_security_data_callbacks(ispi);
+
return 0;
}
@@ -538,7 +590,6 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len,
default:
return -EINVAL;
}
-
}
writel(val, ispi->sregs + SSFSTS_CTL);
@@ -655,7 +706,8 @@ static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len,
/* Read cannot cross 4K boundary */
block_size = min_t(loff_t, from + block_size,
- round_up(from + 1, SZ_4K)) - from;
+ round_up(from + 1, SZ_4K)) -
+ from;
writel(from, ispi->base + FADDR);
@@ -712,7 +764,8 @@ static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len,
/* Write cannot cross 4K boundary */
block_size = min_t(loff_t, to + block_size,
- round_up(to + 1, SZ_4K)) - to;
+ round_up(to + 1, SZ_4K)) -
+ to;
writel(to, ispi->base + FADDR);
@@ -779,8 +832,8 @@ static int intel_spi_erase(struct spi_nor *nor, loff_t offs)
while (len > 0) {
writel(offs, ispi->base + FADDR);
- ret = intel_spi_sw_cycle(ispi, nor->erase_opcode,
- 0, OPTYPE_WRITE_WITH_ADDR);
+ ret = intel_spi_sw_cycle(ispi, nor->erase_opcode, 0,
+ OPTYPE_WRITE_WITH_ADDR);
if (ret)
return ret;
@@ -894,12 +947,11 @@ static const struct spi_nor_controller_ops intel_spi_controller_ops = {
.erase = intel_spi_erase,
};
-struct intel_spi *intel_spi_probe(struct device *dev,
- struct resource *mem, const struct intel_spi_boardinfo *info)
+struct intel_spi *intel_spi_probe(struct device *dev, struct resource *mem,
+ const struct intel_spi_boardinfo *info)
{
const struct spi_nor_hwcaps hwcaps = {
- .mask = SNOR_HWCAPS_READ |
- SNOR_HWCAPS_READ_FAST |
+ .mask = SNOR_HWCAPS_READ | SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_PP,
};
struct mtd_partition part;
diff --git a/include/linux/platform_data/firmware_security_data.h b/include/linux/platform_data/firmware_security_data.h
new file mode 100644
index 000000000000..a73b286644d0
--- /dev/null
+++ b/include/linux/platform_data/firmware_security_data.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Firmware security data kernel module
+ *
+ * Copyright (C) 2020 Daniel Gutson <daniel.gutson@eclypsium.com>
+ * Copyright (C) 2020 Eclypsium Inc.
+ */
+#ifndef FIRMWARE_SECURITY_DATA_H
+#define FIRMWARE_SECURITY_DATA_H
+
+#include <linux/types.h>
+
+extern int register_firmware_security_data_callback(
+ const char *name, ssize_t (*callback)(char *buf, void *private_data),
+ void *private_data);
+
+#endif /* FIRMWARE_SECURITY_DATA_H */
--
2.25.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.