Merge android11-5.4.57 (3f413d0
) into msm-5.4
* refs/heads/tmp-3f413d0: Linux 5.4.57 bpf: sockmap: Require attach_bpf_fd when detaching a program selftests: bpf: Fix detach from sockmap tests ext4: fix direct I/O read error arm64: Workaround circular dependency in pointer_auth.h random32: move the pseudo-random 32-bit definitions to prandom.h random32: remove net_rand_state from the latent entropy gcc plugin random: fix circular include dependency on arm64 after addition of percpu.h ARM: percpu.h: fix build error random32: update the net random state on interrupt and activity ANDROID: Update ABI xml UPSTREAM: of: property: Add device link support for pinctrl-0 through pinctrl-8 UPSTREAM: of: property: Add device link support for multiple DT bindings UPSTREAM: of: property: Add device link support for extcon UPSTREAM: driver core: Change delimiter in devlink device's name to "--" UPSTREAM: driver core: Fix sleeping in invalid context during device link deletion BACKPORT: driver core: Add waiting_for_supplier sysfs file for devices UPSTREAM: driver core: Add state_synced sysfs file for devices that support it UPSTREAM: driver core: Expose device link details in sysfs UPSTREAM: driver core: Avoid deferred probe due to fw_devlink_pause/resume() UPSTREAM: driver core: Rename dev_links_info.defer_sync to defer_hook UPSTREAM: driver core: Don't do deferred probe in parallel with kernel_init thread UPSTREAM: arm64/module: Optimize module load time by optimizing PLT counting FROMGIT: scsi: block: pm: Simplify resume handling Change-Id: Ide67c767b3a0f455ab5cec4b571ab599eae813d5 Signed-off-by: Blagovest Kolenichev <bkolenichev@codeaurora.org>
This commit is contained in:
commit
33a0fb78c7
126
Documentation/ABI/testing/sysfs-class-devlink
Normal file
126
Documentation/ABI/testing/sysfs-class-devlink
Normal file
@ -0,0 +1,126 @@
|
||||
What: /sys/class/devlink/.../
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
Provide a place in sysfs for the device link objects in the
|
||||
kernel at any given time. The name of a device link directory,
|
||||
denoted as ... above, is of the form <supplier>--<consumer>
|
||||
where <supplier> is the supplier device name and <consumer> is
|
||||
the consumer device name.
|
||||
|
||||
What: /sys/class/devlink/.../auto_remove_on
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
This file indicates if the device link will ever be
|
||||
automatically removed by the driver core when the consumer and
|
||||
supplier devices themselves are still present.
|
||||
|
||||
This will be one of the following strings:
|
||||
|
||||
'consumer unbind'
|
||||
'supplier unbind'
|
||||
'never'
|
||||
|
||||
'consumer unbind' means the device link will be removed when
|
||||
the consumer's driver is unbound from the consumer device.
|
||||
|
||||
'supplier unbind' means the device link will be removed when
|
||||
the supplier's driver is unbound from the supplier device.
|
||||
|
||||
'never' means the device link will not be automatically removed
|
||||
when as long as the supplier and consumer devices themselves
|
||||
are still present.
|
||||
|
||||
What: /sys/class/devlink/.../consumer
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
This file is a symlink to the consumer device's sysfs directory.
|
||||
|
||||
What: /sys/class/devlink/.../runtime_pm
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
This file indicates if the device link has any impact on the
|
||||
runtime power management behavior of the consumer and supplier
|
||||
devices. For example: Making sure the supplier doesn't enter
|
||||
runtime suspend while the consumer is active.
|
||||
|
||||
This will be one of the following strings:
|
||||
|
||||
'0' - Does not affect runtime power management
|
||||
'1' - Affects runtime power management
|
||||
|
||||
What: /sys/class/devlink/.../status
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
This file indicates the status of the device link. The status
|
||||
of a device link is affected by whether the supplier and
|
||||
consumer devices have been bound to their corresponding
|
||||
drivers. The status of a device link also affects the binding
|
||||
and unbinding of the supplier and consumer devices with their
|
||||
drivers and also affects whether the software state of the
|
||||
supplier device is synced with the hardware state of the
|
||||
supplier device after boot up.
|
||||
See also: sysfs-devices-state_synced.
|
||||
|
||||
This will be one of the following strings:
|
||||
|
||||
'not tracked'
|
||||
'dormant'
|
||||
'available'
|
||||
'consumer probing'
|
||||
'active'
|
||||
'supplier unbinding'
|
||||
'unknown'
|
||||
|
||||
'not tracked' means this device link does not track the status
|
||||
and has no impact on the binding, unbinding and syncing the
|
||||
hardware and software device state.
|
||||
|
||||
'dormant' means the supplier and the consumer devices have not
|
||||
bound to their driver.
|
||||
|
||||
'available' means the supplier has bound to its driver and is
|
||||
available to supply resources to the consumer device.
|
||||
|
||||
'consumer probing' means the consumer device is currently
|
||||
trying to bind to its driver.
|
||||
|
||||
'active' means the supplier and consumer devices have both
|
||||
bound successfully to their drivers.
|
||||
|
||||
'supplier unbinding' means the supplier devices is currently in
|
||||
the process of unbinding from its driver.
|
||||
|
||||
'unknown' means the state of the device link is not any of the
|
||||
above. If this is ever the value, there's a bug in the kernel.
|
||||
|
||||
What: /sys/class/devlink/.../supplier
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
This file is a symlink to the supplier device's sysfs directory.
|
||||
|
||||
What: /sys/class/devlink/.../sync_state_only
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
This file indicates if the device link is limited to only
|
||||
affecting the syncing of the hardware and software state of the
|
||||
supplier device.
|
||||
|
||||
This will be one of the following strings:
|
||||
|
||||
'0'
|
||||
'1' - Affects runtime power management
|
||||
|
||||
'0' means the device link can affect other device behaviors
|
||||
like binding/unbinding, suspend/resume, runtime power
|
||||
management, etc.
|
||||
|
||||
'1' means the device link will only affect the syncing of
|
||||
hardware and software state of the supplier device after boot
|
||||
up and doesn't not affect other behaviors of the devices.
|
8
Documentation/ABI/testing/sysfs-devices-consumer
Normal file
8
Documentation/ABI/testing/sysfs-devices-consumer
Normal file
@ -0,0 +1,8 @@
|
||||
What: /sys/devices/.../consumer:<consumer>
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
The /sys/devices/.../consumer:<consumer> are symlinks to device
|
||||
links where this device is the supplier. <consumer> denotes the
|
||||
name of the consumer in that device link. There can be zero or
|
||||
more of these symlinks for a given device.
|
24
Documentation/ABI/testing/sysfs-devices-state_synced
Normal file
24
Documentation/ABI/testing/sysfs-devices-state_synced
Normal file
@ -0,0 +1,24 @@
|
||||
What: /sys/devices/.../state_synced
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
The /sys/devices/.../state_synced attribute is only present for
|
||||
devices whose bus types or driver provides the .sync_state()
|
||||
callback. The number read from it (0 or 1) reflects the value
|
||||
of the device's 'state_synced' field. A value of 0 means the
|
||||
.sync_state() callback hasn't been called yet. A value of 1
|
||||
means the .sync_state() callback has been called.
|
||||
|
||||
Generally, if a device has sync_state() support and has some of
|
||||
the resources it provides enabled at the time the kernel starts
|
||||
(Eg: enabled by hardware reset or bootloader or anything that
|
||||
run before the kernel starts), then it'll keep those resources
|
||||
enabled and in a state that's compatible with the state they
|
||||
were in at the start of the kernel. The device will stop doing
|
||||
this only when the sync_state() callback has been called --
|
||||
which happens only when all its consumer devices are registered
|
||||
and have probed successfully. Resources that were left disabled
|
||||
at the time the kernel starts are not affected or limited in
|
||||
any way by sync_state() callbacks.
|
||||
|
||||
|
8
Documentation/ABI/testing/sysfs-devices-supplier
Normal file
8
Documentation/ABI/testing/sysfs-devices-supplier
Normal file
@ -0,0 +1,8 @@
|
||||
What: /sys/devices/.../supplier:<supplier>
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
The /sys/devices/.../supplier:<supplier> are symlinks to device
|
||||
links where this device is the consumer. <supplier> denotes the
|
||||
name of the supplier in that device link. There can be zero or
|
||||
more of these symlinks for a given device.
|
17
Documentation/ABI/testing/sysfs-devices-waiting_for_supplier
Normal file
17
Documentation/ABI/testing/sysfs-devices-waiting_for_supplier
Normal file
@ -0,0 +1,17 @@
|
||||
What: /sys/devices/.../waiting_for_supplier
|
||||
Date: May 2020
|
||||
Contact: Saravana Kannan <saravanak@google.com>
|
||||
Description:
|
||||
The /sys/devices/.../waiting_for_supplier attribute is only
|
||||
present when fw_devlink kernel command line option is enabled
|
||||
and is set to something stricter than "permissive". It is
|
||||
removed once a device probes successfully (because the
|
||||
information is no longer relevant). The number read from it (0
|
||||
or 1) reflects whether the device is waiting for one or more
|
||||
suppliers to be added and then linked to using device links
|
||||
before the device can probe.
|
||||
|
||||
A value of 0 means the device is not waiting for any suppliers
|
||||
to be added before it can probe. A value of 1 means the device
|
||||
is waiting for one or more suppliers to be added before it can
|
||||
probe.
|
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 56
|
||||
SUBLEVEL = 57
|
||||
EXTRAVERSION =
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,8 @@
|
||||
#ifndef _ASM_ARM_PERCPU_H_
|
||||
#define _ASM_ARM_PERCPU_H_
|
||||
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
/*
|
||||
* Same as asm-generic/percpu.h, except that we store the per cpu offset
|
||||
* in the TPIDRPRW. TPIDRPRW only exists on V6K and V7
|
||||
|
@ -3,7 +3,6 @@
|
||||
#define __ASM_POINTER_AUTH_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/memory.h>
|
||||
@ -30,6 +29,13 @@ struct ptrauth_keys {
|
||||
struct ptrauth_key apga;
|
||||
};
|
||||
|
||||
/*
|
||||
* Only include random.h once ptrauth_keys_* structures are defined
|
||||
* to avoid yet another circular include hell (random.h * ends up
|
||||
* including asm/smp.h, which requires ptrauth_keys_kernel).
|
||||
*/
|
||||
#include <linux/random.h>
|
||||
|
||||
static inline void ptrauth_keys_init(struct ptrauth_keys *keys)
|
||||
{
|
||||
if (system_supports_address_auth()) {
|
||||
|
@ -252,6 +252,40 @@ static unsigned int count_plts(Elf64_Sym *syms, Elf64_Rela *rela, int num,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool branch_rela_needs_plt(Elf64_Sym *syms, Elf64_Rela *rela,
|
||||
Elf64_Word dstidx)
|
||||
{
|
||||
|
||||
Elf64_Sym *s = syms + ELF64_R_SYM(rela->r_info);
|
||||
|
||||
if (s->st_shndx == dstidx)
|
||||
return false;
|
||||
|
||||
return ELF64_R_TYPE(rela->r_info) == R_AARCH64_JUMP26 ||
|
||||
ELF64_R_TYPE(rela->r_info) == R_AARCH64_CALL26;
|
||||
}
|
||||
|
||||
/* Group branch PLT relas at the front end of the array. */
|
||||
static int partition_branch_plt_relas(Elf64_Sym *syms, Elf64_Rela *rela,
|
||||
int numrels, Elf64_Word dstidx)
|
||||
{
|
||||
int i = 0, j = numrels - 1;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_RANDOMIZE_BASE))
|
||||
return 0;
|
||||
|
||||
while (i < j) {
|
||||
if (branch_rela_needs_plt(syms, &rela[i], dstidx))
|
||||
i++;
|
||||
else if (branch_rela_needs_plt(syms, &rela[j], dstidx))
|
||||
swap(rela[i], rela[j]);
|
||||
else
|
||||
j--;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
char *secstrings, struct module *mod)
|
||||
{
|
||||
@ -289,7 +323,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
|
||||
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||
Elf64_Rela *rels = (void *)ehdr + sechdrs[i].sh_offset;
|
||||
int numrels = sechdrs[i].sh_size / sizeof(Elf64_Rela);
|
||||
int nents, numrels = sechdrs[i].sh_size / sizeof(Elf64_Rela);
|
||||
Elf64_Shdr *dstsec = sechdrs + sechdrs[i].sh_info;
|
||||
|
||||
if (sechdrs[i].sh_type != SHT_RELA)
|
||||
@ -299,8 +333,14 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
if (!(dstsec->sh_flags & SHF_EXECINSTR))
|
||||
continue;
|
||||
|
||||
/* sort by type, symbol index and addend */
|
||||
sort(rels, numrels, sizeof(Elf64_Rela), cmp_rela, NULL);
|
||||
/*
|
||||
* sort branch relocations requiring a PLT by type, symbol index
|
||||
* and addend
|
||||
*/
|
||||
nents = partition_branch_plt_relas(syms, rels, numrels,
|
||||
sechdrs[i].sh_info);
|
||||
if (nents)
|
||||
sort(rels, nents, sizeof(Elf64_Rela), cmp_rela, NULL);
|
||||
|
||||
if (!str_has_prefix(secstrings + dstsec->sh_name, ".init"))
|
||||
core_plts += count_plts(syms, rels, numrels,
|
||||
|
@ -164,9 +164,8 @@ EXPORT_SYMBOL(blk_pre_runtime_resume);
|
||||
*
|
||||
* Description:
|
||||
* Update the queue's runtime status according to the return value of the
|
||||
* device's runtime_resume function. If it is successfully resumed, process
|
||||
* the requests that are queued into the device's queue when it is resuming
|
||||
* and then mark last busy and initiate autosuspend for it.
|
||||
* device's runtime_resume function. If the resume was successful, call
|
||||
* blk_set_runtime_active() to do the real work of restarting the queue.
|
||||
*
|
||||
* This function should be called near the end of the device's
|
||||
* runtime_resume callback.
|
||||
@ -175,19 +174,13 @@ void blk_post_runtime_resume(struct request_queue *q, int err)
|
||||
{
|
||||
if (!q->dev)
|
||||
return;
|
||||
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
if (!err) {
|
||||
q->rpm_status = RPM_ACTIVE;
|
||||
pm_runtime_mark_last_busy(q->dev);
|
||||
pm_request_autosuspend(q->dev);
|
||||
blk_set_runtime_active(q);
|
||||
} else {
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
q->rpm_status = RPM_SUSPENDED;
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
}
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
|
||||
if (!err)
|
||||
blk_clear_pm_only(q);
|
||||
}
|
||||
EXPORT_SYMBOL(blk_post_runtime_resume);
|
||||
|
||||
@ -204,15 +197,25 @@ EXPORT_SYMBOL(blk_post_runtime_resume);
|
||||
* This function can be used in driver's resume hook to correct queue
|
||||
* runtime PM status and re-enable peeking requests from the queue. It
|
||||
* should be called before first request is added to the queue.
|
||||
*
|
||||
* This function is also called by blk_post_runtime_resume() for successful
|
||||
* runtime resumes. It does everything necessary to restart the queue.
|
||||
*/
|
||||
void blk_set_runtime_active(struct request_queue *q)
|
||||
{
|
||||
if (q->dev) {
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
q->rpm_status = RPM_ACTIVE;
|
||||
pm_runtime_mark_last_busy(q->dev);
|
||||
pm_request_autosuspend(q->dev);
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
}
|
||||
int old_status;
|
||||
|
||||
if (!q->dev)
|
||||
return;
|
||||
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
old_status = q->rpm_status;
|
||||
q->rpm_status = RPM_ACTIVE;
|
||||
pm_runtime_mark_last_busy(q->dev);
|
||||
pm_request_autosuspend(q->dev);
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
|
||||
if (old_status != RPM_ACTIVE)
|
||||
blk_clear_pm_only(q);
|
||||
}
|
||||
EXPORT_SYMBOL(blk_set_runtime_active);
|
||||
|
@ -142,7 +142,6 @@ extern char *make_class_name(const char *name, struct kobject *kobj);
|
||||
extern int devres_release_all(struct device *dev);
|
||||
extern void device_block_probing(void);
|
||||
extern void device_unblock_probing(void);
|
||||
extern void driver_deferred_probe_force_trigger(void);
|
||||
|
||||
/* /sys/devices directory */
|
||||
extern struct kset *devices_kset;
|
||||
|
@ -50,6 +50,7 @@ static DEFINE_MUTEX(wfs_lock);
|
||||
static LIST_HEAD(deferred_sync);
|
||||
static unsigned int defer_sync_state_count = 1;
|
||||
static unsigned int defer_fw_devlink_count;
|
||||
static LIST_HEAD(deferred_fw_devlink);
|
||||
static DEFINE_MUTEX(defer_fw_devlink_lock);
|
||||
|
||||
#ifdef CONFIG_SRCU
|
||||
@ -234,6 +235,210 @@ void device_pm_move_to_tail(struct device *dev)
|
||||
device_links_read_unlock(idx);
|
||||
}
|
||||
|
||||
#define to_devlink(dev) container_of((dev), struct device_link, link_dev)
|
||||
|
||||
static ssize_t status_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
char *status;
|
||||
|
||||
switch (to_devlink(dev)->status) {
|
||||
case DL_STATE_NONE:
|
||||
status = "not tracked"; break;
|
||||
case DL_STATE_DORMANT:
|
||||
status = "dormant"; break;
|
||||
case DL_STATE_AVAILABLE:
|
||||
status = "available"; break;
|
||||
case DL_STATE_CONSUMER_PROBE:
|
||||
status = "consumer probing"; break;
|
||||
case DL_STATE_ACTIVE:
|
||||
status = "active"; break;
|
||||
case DL_STATE_SUPPLIER_UNBIND:
|
||||
status = "supplier unbinding"; break;
|
||||
default:
|
||||
status = "unknown"; break;
|
||||
}
|
||||
return sprintf(buf, "%s\n", status);
|
||||
}
|
||||
static DEVICE_ATTR_RO(status);
|
||||
|
||||
static ssize_t auto_remove_on_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
char *str;
|
||||
|
||||
if (link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
|
||||
str = "supplier unbind";
|
||||
else if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)
|
||||
str = "consumer unbind";
|
||||
else
|
||||
str = "never";
|
||||
|
||||
return sprintf(buf, "%s\n", str);
|
||||
}
|
||||
static DEVICE_ATTR_RO(auto_remove_on);
|
||||
|
||||
static ssize_t runtime_pm_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_PM_RUNTIME));
|
||||
}
|
||||
static DEVICE_ATTR_RO(runtime_pm);
|
||||
|
||||
static ssize_t sync_state_only_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", !!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
|
||||
}
|
||||
static DEVICE_ATTR_RO(sync_state_only);
|
||||
|
||||
static struct attribute *devlink_attrs[] = {
|
||||
&dev_attr_status.attr,
|
||||
&dev_attr_auto_remove_on.attr,
|
||||
&dev_attr_runtime_pm.attr,
|
||||
&dev_attr_sync_state_only.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(devlink);
|
||||
|
||||
static void device_link_free(struct device_link *link)
|
||||
{
|
||||
while (refcount_dec_not_one(&link->rpm_active))
|
||||
pm_runtime_put(link->supplier);
|
||||
|
||||
put_device(link->consumer);
|
||||
put_device(link->supplier);
|
||||
kfree(link);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SRCU
|
||||
static void __device_link_free_srcu(struct rcu_head *rhead)
|
||||
{
|
||||
device_link_free(container_of(rhead, struct device_link, rcu_head));
|
||||
}
|
||||
|
||||
static void devlink_dev_release(struct device *dev)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
|
||||
call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu);
|
||||
}
|
||||
#else
|
||||
static void devlink_dev_release(struct device *dev)
|
||||
{
|
||||
device_link_free(to_devlink(dev));
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct class devlink_class = {
|
||||
.name = "devlink",
|
||||
.owner = THIS_MODULE,
|
||||
.dev_groups = devlink_groups,
|
||||
.dev_release = devlink_dev_release,
|
||||
};
|
||||
|
||||
static int devlink_add_symlinks(struct device *dev,
|
||||
struct class_interface *class_intf)
|
||||
{
|
||||
int ret;
|
||||
size_t len;
|
||||
struct device_link *link = to_devlink(dev);
|
||||
struct device *sup = link->supplier;
|
||||
struct device *con = link->consumer;
|
||||
char *buf;
|
||||
|
||||
len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
|
||||
len += strlen("supplier:") + 1;
|
||||
buf = kzalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = sysfs_create_link(&link->link_dev.kobj, &sup->kobj, "supplier");
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = sysfs_create_link(&link->link_dev.kobj, &con->kobj, "consumer");
|
||||
if (ret)
|
||||
goto err_con;
|
||||
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf);
|
||||
if (ret)
|
||||
goto err_con_dev;
|
||||
|
||||
snprintf(buf, len, "supplier:%s", dev_name(sup));
|
||||
ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf);
|
||||
if (ret)
|
||||
goto err_sup_dev;
|
||||
|
||||
goto out;
|
||||
|
||||
err_sup_dev:
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
sysfs_remove_link(&sup->kobj, buf);
|
||||
err_con_dev:
|
||||
sysfs_remove_link(&link->link_dev.kobj, "consumer");
|
||||
err_con:
|
||||
sysfs_remove_link(&link->link_dev.kobj, "supplier");
|
||||
out:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void devlink_remove_symlinks(struct device *dev,
|
||||
struct class_interface *class_intf)
|
||||
{
|
||||
struct device_link *link = to_devlink(dev);
|
||||
size_t len;
|
||||
struct device *sup = link->supplier;
|
||||
struct device *con = link->consumer;
|
||||
char *buf;
|
||||
|
||||
sysfs_remove_link(&link->link_dev.kobj, "consumer");
|
||||
sysfs_remove_link(&link->link_dev.kobj, "supplier");
|
||||
|
||||
len = max(strlen(dev_name(sup)), strlen(dev_name(con)));
|
||||
len += strlen("supplier:") + 1;
|
||||
buf = kzalloc(len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
WARN(1, "Unable to properly free device link symlinks!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, len, "supplier:%s", dev_name(sup));
|
||||
sysfs_remove_link(&con->kobj, buf);
|
||||
snprintf(buf, len, "consumer:%s", dev_name(con));
|
||||
sysfs_remove_link(&sup->kobj, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static struct class_interface devlink_class_intf = {
|
||||
.class = &devlink_class,
|
||||
.add_dev = devlink_add_symlinks,
|
||||
.remove_dev = devlink_remove_symlinks,
|
||||
};
|
||||
|
||||
static int __init devlink_class_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = class_register(&devlink_class);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = class_interface_register(&devlink_class_intf);
|
||||
if (ret)
|
||||
class_unregister(&devlink_class);
|
||||
|
||||
return ret;
|
||||
}
|
||||
postcore_initcall(devlink_class_init);
|
||||
|
||||
#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \
|
||||
DL_FLAG_AUTOREMOVE_SUPPLIER | \
|
||||
DL_FLAG_AUTOPROBE_CONSUMER | \
|
||||
@ -406,13 +611,6 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
|
||||
refcount_set(&link->rpm_active, 1);
|
||||
|
||||
if (flags & DL_FLAG_PM_RUNTIME) {
|
||||
if (flags & DL_FLAG_RPM_ACTIVE)
|
||||
refcount_inc(&link->rpm_active);
|
||||
|
||||
pm_runtime_new_link(consumer);
|
||||
}
|
||||
|
||||
get_device(supplier);
|
||||
link->supplier = supplier;
|
||||
INIT_LIST_HEAD(&link->s_node);
|
||||
@ -422,6 +620,25 @@ struct device_link *device_link_add(struct device *consumer,
|
||||
link->flags = flags;
|
||||
kref_init(&link->kref);
|
||||
|
||||
link->link_dev.class = &devlink_class;
|
||||
device_set_pm_not_required(&link->link_dev);
|
||||
dev_set_name(&link->link_dev, "%s--%s",
|
||||
dev_name(supplier), dev_name(consumer));
|
||||
if (device_register(&link->link_dev)) {
|
||||
put_device(consumer);
|
||||
put_device(supplier);
|
||||
kfree(link);
|
||||
link = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & DL_FLAG_PM_RUNTIME) {
|
||||
if (flags & DL_FLAG_RPM_ACTIVE)
|
||||
refcount_inc(&link->rpm_active);
|
||||
|
||||
pm_runtime_new_link(consumer);
|
||||
}
|
||||
|
||||
/* Determine the initial link state. */
|
||||
if (flags & DL_FLAG_STATELESS)
|
||||
link->status = DL_STATE_NONE;
|
||||
@ -537,22 +754,7 @@ static void device_link_add_missing_supplier_links(void)
|
||||
mutex_unlock(&wfs_lock);
|
||||
}
|
||||
|
||||
static void device_link_free(struct device_link *link)
|
||||
{
|
||||
while (refcount_dec_not_one(&link->rpm_active))
|
||||
pm_runtime_put(link->supplier);
|
||||
|
||||
put_device(link->consumer);
|
||||
put_device(link->supplier);
|
||||
kfree(link);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SRCU
|
||||
static void __device_link_free_srcu(struct rcu_head *rhead)
|
||||
{
|
||||
device_link_free(container_of(rhead, struct device_link, rcu_head));
|
||||
}
|
||||
|
||||
static void __device_link_del(struct kref *kref)
|
||||
{
|
||||
struct device_link *link = container_of(kref, struct device_link, kref);
|
||||
@ -565,7 +767,7 @@ static void __device_link_del(struct kref *kref)
|
||||
|
||||
list_del_rcu(&link->s_node);
|
||||
list_del_rcu(&link->c_node);
|
||||
call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu);
|
||||
device_unregister(&link->link_dev);
|
||||
}
|
||||
#else /* !CONFIG_SRCU */
|
||||
static void __device_link_del(struct kref *kref)
|
||||
@ -580,7 +782,7 @@ static void __device_link_del(struct kref *kref)
|
||||
|
||||
list_del(&link->s_node);
|
||||
list_del(&link->c_node);
|
||||
device_link_free(link);
|
||||
device_unregister(&link->link_dev);
|
||||
}
|
||||
#endif /* !CONFIG_SRCU */
|
||||
|
||||
@ -753,11 +955,11 @@ static void __device_links_queue_sync_state(struct device *dev,
|
||||
*/
|
||||
dev->state_synced = true;
|
||||
|
||||
if (WARN_ON(!list_empty(&dev->links.defer_sync)))
|
||||
if (WARN_ON(!list_empty(&dev->links.defer_hook)))
|
||||
return;
|
||||
|
||||
get_device(dev);
|
||||
list_add_tail(&dev->links.defer_sync, list);
|
||||
list_add_tail(&dev->links.defer_hook, list);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -775,8 +977,8 @@ static void device_links_flush_sync_list(struct list_head *list,
|
||||
{
|
||||
struct device *dev, *tmp;
|
||||
|
||||
list_for_each_entry_safe(dev, tmp, list, links.defer_sync) {
|
||||
list_del_init(&dev->links.defer_sync);
|
||||
list_for_each_entry_safe(dev, tmp, list, links.defer_hook) {
|
||||
list_del_init(&dev->links.defer_hook);
|
||||
|
||||
if (dev != dont_lock_dev)
|
||||
device_lock(dev);
|
||||
@ -814,12 +1016,12 @@ void device_links_supplier_sync_state_resume(void)
|
||||
if (defer_sync_state_count)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_sync) {
|
||||
list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_hook) {
|
||||
/*
|
||||
* Delete from deferred_sync list before queuing it to
|
||||
* sync_list because defer_sync is used for both lists.
|
||||
* sync_list because defer_hook is used for both lists.
|
||||
*/
|
||||
list_del_init(&dev->links.defer_sync);
|
||||
list_del_init(&dev->links.defer_hook);
|
||||
__device_links_queue_sync_state(dev, &sync_list);
|
||||
}
|
||||
out:
|
||||
@ -837,8 +1039,8 @@ late_initcall(sync_state_resume_initcall);
|
||||
|
||||
static void __device_links_supplier_defer_sync(struct device *sup)
|
||||
{
|
||||
if (list_empty(&sup->links.defer_sync) && dev_has_sync_state(sup))
|
||||
list_add_tail(&sup->links.defer_sync, &deferred_sync);
|
||||
if (list_empty(&sup->links.defer_hook) && dev_has_sync_state(sup))
|
||||
list_add_tail(&sup->links.defer_hook, &deferred_sync);
|
||||
}
|
||||
|
||||
static void device_link_drop_managed(struct device_link *link)
|
||||
@ -848,6 +1050,22 @@ static void device_link_drop_managed(struct device_link *link)
|
||||
kref_put(&link->kref, __device_link_del);
|
||||
}
|
||||
|
||||
static ssize_t waiting_for_supplier_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
bool val;
|
||||
|
||||
device_lock(dev);
|
||||
mutex_lock(&wfs_lock);
|
||||
val = !list_empty(&dev->links.needs_suppliers)
|
||||
&& dev->links.need_for_probe;
|
||||
mutex_unlock(&wfs_lock);
|
||||
device_unlock(dev);
|
||||
return sprintf(buf, "%u\n", val);
|
||||
}
|
||||
static DEVICE_ATTR_RO(waiting_for_supplier);
|
||||
|
||||
/**
|
||||
* device_links_driver_bound - Update device links after probing its driver.
|
||||
* @dev: Device to update the links for.
|
||||
@ -872,6 +1090,7 @@ void device_links_driver_bound(struct device *dev)
|
||||
mutex_lock(&wfs_lock);
|
||||
list_del_init(&dev->links.needs_suppliers);
|
||||
mutex_unlock(&wfs_lock);
|
||||
device_remove_file(dev, &dev_attr_waiting_for_supplier);
|
||||
|
||||
device_links_write_lock();
|
||||
|
||||
@ -1051,7 +1270,7 @@ void device_links_driver_cleanup(struct device *dev)
|
||||
WRITE_ONCE(link->status, DL_STATE_DORMANT);
|
||||
}
|
||||
|
||||
list_del_init(&dev->links.defer_sync);
|
||||
list_del_init(&dev->links.defer_hook);
|
||||
__device_links_no_driver(dev);
|
||||
|
||||
device_links_write_unlock();
|
||||
@ -1158,6 +1377,9 @@ static void device_links_purge(struct device *dev)
|
||||
{
|
||||
struct device_link *link, *ln;
|
||||
|
||||
if (dev->class == &devlink_class)
|
||||
return;
|
||||
|
||||
mutex_lock(&wfs_lock);
|
||||
list_del(&dev->links.needs_suppliers);
|
||||
mutex_unlock(&wfs_lock);
|
||||
@ -1208,6 +1430,12 @@ static void fw_devlink_link_device(struct device *dev)
|
||||
fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
|
||||
} else {
|
||||
fw_ret = -ENODEV;
|
||||
/*
|
||||
* defer_hook is not used to add device to deferred_sync list
|
||||
* until device is bound. Since deferred fw devlink also blocks
|
||||
* probing, same list hook can be used for deferred_fw_devlink.
|
||||
*/
|
||||
list_add_tail(&dev->links.defer_hook, &deferred_fw_devlink);
|
||||
}
|
||||
|
||||
if (fw_ret == -ENODEV)
|
||||
@ -1276,6 +1504,9 @@ void fw_devlink_pause(void)
|
||||
*/
|
||||
void fw_devlink_resume(void)
|
||||
{
|
||||
struct device *dev, *tmp;
|
||||
LIST_HEAD(probe_list);
|
||||
|
||||
mutex_lock(&defer_fw_devlink_lock);
|
||||
if (!defer_fw_devlink_count) {
|
||||
WARN(true, "Unmatched fw_devlink pause/resume!");
|
||||
@ -1287,9 +1518,19 @@ void fw_devlink_resume(void)
|
||||
goto out;
|
||||
|
||||
device_link_add_missing_supplier_links();
|
||||
driver_deferred_probe_force_trigger();
|
||||
list_splice_tail_init(&deferred_fw_devlink, &probe_list);
|
||||
out:
|
||||
mutex_unlock(&defer_fw_devlink_lock);
|
||||
|
||||
/*
|
||||
* bus_probe_device() can cause new devices to get added and they'll
|
||||
* try to grab defer_fw_devlink_lock. So, this needs to be done outside
|
||||
* the defer_fw_devlink_lock.
|
||||
*/
|
||||
list_for_each_entry_safe(dev, tmp, &probe_list, links.defer_hook) {
|
||||
list_del_init(&dev->links.defer_hook);
|
||||
bus_probe_device(dev);
|
||||
}
|
||||
}
|
||||
/* Device links support end. */
|
||||
|
||||
@ -1925,8 +2166,14 @@ static int device_add_attrs(struct device *dev)
|
||||
goto err_remove_dev_groups;
|
||||
}
|
||||
|
||||
error = device_create_file(dev, &dev_attr_waiting_for_supplier);
|
||||
if (error)
|
||||
goto err_remove_dev_online;
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_dev_online:
|
||||
device_remove_file(dev, &dev_attr_online);
|
||||
err_remove_dev_groups:
|
||||
device_remove_groups(dev, dev->groups);
|
||||
err_remove_type_groups:
|
||||
@ -1944,6 +2191,7 @@ static void device_remove_attrs(struct device *dev)
|
||||
struct class *class = dev->class;
|
||||
const struct device_type *type = dev->type;
|
||||
|
||||
device_remove_file(dev, &dev_attr_waiting_for_supplier);
|
||||
device_remove_file(dev, &dev_attr_online);
|
||||
device_remove_groups(dev, dev->groups);
|
||||
|
||||
@ -2148,7 +2396,7 @@ void device_initialize(struct device *dev)
|
||||
INIT_LIST_HEAD(&dev->links.consumers);
|
||||
INIT_LIST_HEAD(&dev->links.suppliers);
|
||||
INIT_LIST_HEAD(&dev->links.needs_suppliers);
|
||||
INIT_LIST_HEAD(&dev->links.defer_sync);
|
||||
INIT_LIST_HEAD(&dev->links.defer_hook);
|
||||
dev->links.status = DL_DEV_NO_DRIVER;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_initialize);
|
||||
|
@ -164,11 +164,6 @@ static void driver_deferred_probe_trigger(void)
|
||||
if (!driver_deferred_probe_enable)
|
||||
return;
|
||||
|
||||
driver_deferred_probe_force_trigger();
|
||||
}
|
||||
|
||||
void driver_deferred_probe_force_trigger(void)
|
||||
{
|
||||
/*
|
||||
* A successful probe means that all the devices in the pending list
|
||||
* should be triggered to be reprobed. Move all the deferred devices
|
||||
@ -494,6 +489,18 @@ static void driver_deferred_probe_add_trigger(struct device *dev,
|
||||
driver_deferred_probe_trigger();
|
||||
}
|
||||
|
||||
static ssize_t state_synced_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
bool val;
|
||||
|
||||
device_lock(dev);
|
||||
val = dev->state_synced;
|
||||
device_unlock(dev);
|
||||
return sprintf(buf, "%u\n", val);
|
||||
}
|
||||
static DEVICE_ATTR_RO(state_synced);
|
||||
|
||||
static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
int ret = -EPROBE_DEFER;
|
||||
@ -567,9 +574,16 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
goto dev_groups_failed;
|
||||
}
|
||||
|
||||
if (dev_has_sync_state(dev) &&
|
||||
device_create_file(dev, &dev_attr_state_synced)) {
|
||||
dev_err(dev, "state_synced sysfs add failed\n");
|
||||
goto dev_sysfs_state_synced_failed;
|
||||
}
|
||||
|
||||
if (test_remove) {
|
||||
test_remove = false;
|
||||
|
||||
device_remove_file(dev, &dev_attr_state_synced);
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
|
||||
if (dev->bus->remove)
|
||||
@ -599,6 +613,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
|
||||
drv->bus->name, __func__, dev_name(dev), drv->name);
|
||||
goto done;
|
||||
|
||||
dev_sysfs_state_synced_failed:
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
dev_groups_failed:
|
||||
if (dev->bus->remove)
|
||||
dev->bus->remove(dev);
|
||||
@ -1134,6 +1150,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
device_remove_file(dev, &dev_attr_state_synced);
|
||||
device_remove_groups(dev, drv->dev_groups);
|
||||
|
||||
if (dev->bus && dev->bus->remove)
|
||||
|
@ -1249,6 +1249,7 @@ void add_interrupt_randomness(int irq, int irq_flags)
|
||||
|
||||
fast_mix(fast_pool);
|
||||
add_interrupt_bench(cycles);
|
||||
this_cpu_add(net_rand_state.s1, fast_pool->pool[cycles & 3]);
|
||||
|
||||
if (unlikely(crng_init == 0)) {
|
||||
if ((fast_pool->count >= 64) &&
|
||||
|
@ -1192,6 +1192,21 @@ DEFINE_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL)
|
||||
DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells")
|
||||
DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells")
|
||||
DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells")
|
||||
DEFINE_SIMPLE_PROP(extcon, "extcon", NULL)
|
||||
DEFINE_SIMPLE_PROP(interrupts_extended, "interrupts-extended",
|
||||
"#interrupt-cells")
|
||||
DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", NULL)
|
||||
DEFINE_SIMPLE_PROP(phys, "phys", "#phy-cells")
|
||||
DEFINE_SIMPLE_PROP(wakeup_parent, "wakeup-parent", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl0, "pinctrl-0", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl1, "pinctrl-1", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl2, "pinctrl-2", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl3, "pinctrl-3", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl4, "pinctrl-4", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl5, "pinctrl-5", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl6, "pinctrl-6", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl7, "pinctrl-7", NULL)
|
||||
DEFINE_SIMPLE_PROP(pinctrl8, "pinctrl-8", NULL)
|
||||
DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
|
||||
DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
|
||||
DEFINE_SUFFIX_PROP(gpios, "-gpios", "#gpio-cells")
|
||||
@ -1216,6 +1231,20 @@ static const struct supplier_bindings of_supplier_bindings[] = {
|
||||
{ .parse_prop = parse_dmas, },
|
||||
{ .parse_prop = parse_power_domains, },
|
||||
{ .parse_prop = parse_hwlocks, },
|
||||
{ .parse_prop = parse_extcon, },
|
||||
{ .parse_prop = parse_interrupts_extended, },
|
||||
{ .parse_prop = parse_nvmem_cells, },
|
||||
{ .parse_prop = parse_phys, },
|
||||
{ .parse_prop = parse_wakeup_parent, },
|
||||
{ .parse_prop = parse_pinctrl0, },
|
||||
{ .parse_prop = parse_pinctrl1, },
|
||||
{ .parse_prop = parse_pinctrl2, },
|
||||
{ .parse_prop = parse_pinctrl3, },
|
||||
{ .parse_prop = parse_pinctrl4, },
|
||||
{ .parse_prop = parse_pinctrl5, },
|
||||
{ .parse_prop = parse_pinctrl6, },
|
||||
{ .parse_prop = parse_pinctrl7, },
|
||||
{ .parse_prop = parse_pinctrl8, },
|
||||
{ .parse_prop = parse_regulators, },
|
||||
{ .parse_prop = parse_gpio, },
|
||||
{ .parse_prop = parse_gpios, },
|
||||
|
@ -80,10 +80,6 @@ static int scsi_dev_type_resume(struct device *dev,
|
||||
dev_dbg(dev, "scsi resume: %d\n", err);
|
||||
|
||||
if (err == 0) {
|
||||
bool was_runtime_suspended;
|
||||
|
||||
was_runtime_suspended = pm_runtime_suspended(dev);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
err = pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
@ -97,10 +93,8 @@ static int scsi_dev_type_resume(struct device *dev,
|
||||
*/
|
||||
if (!err && scsi_is_sdev_device(dev)) {
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
if (was_runtime_suspended)
|
||||
blk_post_runtime_resume(sdev->request_queue, 0);
|
||||
else
|
||||
blk_set_runtime_active(sdev->request_queue);
|
||||
|
||||
blk_set_runtime_active(sdev->request_queue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3860,6 +3860,11 @@ static ssize_t ext4_direct_IO_read(struct kiocb *iocb, struct iov_iter *iter)
|
||||
struct inode *inode = mapping->host;
|
||||
size_t count = iov_iter_count(iter);
|
||||
ssize_t ret;
|
||||
loff_t offset = iocb->ki_pos;
|
||||
loff_t size = i_size_read(inode);
|
||||
|
||||
if (offset >= size)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Shared inode_lock is enough for us - it protects against concurrent
|
||||
|
@ -956,11 +956,14 @@ static inline void bpf_map_offload_map_free(struct bpf_map *map)
|
||||
#endif /* CONFIG_NET && CONFIG_BPF_SYSCALL */
|
||||
|
||||
#if defined(CONFIG_BPF_STREAM_PARSER)
|
||||
int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog, u32 which);
|
||||
int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog,
|
||||
struct bpf_prog *old, u32 which);
|
||||
int sock_map_get_from_fd(const union bpf_attr *attr, struct bpf_prog *prog);
|
||||
int sock_map_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype);
|
||||
#else
|
||||
static inline int sock_map_prog_update(struct bpf_map *map,
|
||||
struct bpf_prog *prog, u32 which)
|
||||
struct bpf_prog *prog,
|
||||
struct bpf_prog *old, u32 which)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@ -970,6 +973,12 @@ static inline int sock_map_get_from_fd(const union bpf_attr *attr,
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int sock_map_prog_detach(const union bpf_attr *attr,
|
||||
enum bpf_prog_type ptype)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_XDP_SOCKETS)
|
||||
|
@ -1123,34 +1123,6 @@ enum device_link_state {
|
||||
#define DL_FLAG_MANAGED BIT(6)
|
||||
#define DL_FLAG_SYNC_STATE_ONLY BIT(7)
|
||||
|
||||
/**
|
||||
* struct device_link - Device link representation.
|
||||
* @supplier: The device on the supplier end of the link.
|
||||
* @s_node: Hook to the supplier device's list of links to consumers.
|
||||
* @consumer: The device on the consumer end of the link.
|
||||
* @c_node: Hook to the consumer device's list of links to suppliers.
|
||||
* @status: The state of the link (with respect to the presence of drivers).
|
||||
* @flags: Link flags.
|
||||
* @rpm_active: Whether or not the consumer device is runtime-PM-active.
|
||||
* @kref: Count repeated addition of the same link.
|
||||
* @rcu_head: An RCU head to use for deferred execution of SRCU callbacks.
|
||||
* @supplier_preactivated: Supplier has been made active before consumer probe.
|
||||
*/
|
||||
struct device_link {
|
||||
struct device *supplier;
|
||||
struct list_head s_node;
|
||||
struct device *consumer;
|
||||
struct list_head c_node;
|
||||
enum device_link_state status;
|
||||
u32 flags;
|
||||
refcount_t rpm_active;
|
||||
struct kref kref;
|
||||
#ifdef CONFIG_SRCU
|
||||
struct rcu_head rcu_head;
|
||||
#endif
|
||||
bool supplier_preactivated; /* Owned by consumer probe. */
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dl_dev_state - Device driver presence tracking information.
|
||||
* @DL_DEV_NO_DRIVER: There is no driver attached to the device.
|
||||
@ -1170,7 +1142,8 @@ enum dl_dev_state {
|
||||
* @suppliers: List of links to supplier devices.
|
||||
* @consumers: List of links to consumer devices.
|
||||
* @needs_suppliers: Hook to global list of devices waiting for suppliers.
|
||||
* @defer_sync: Hook to global list of devices that have deferred sync_state.
|
||||
* @defer_hook: Hook to global list of devices that have deferred sync_state or
|
||||
* deferred fw_devlink.
|
||||
* @need_for_probe: If needs_suppliers is on a list, this indicates if the
|
||||
* suppliers are needed for probe or not.
|
||||
* @status: Driver status information.
|
||||
@ -1179,7 +1152,7 @@ struct dev_links_info {
|
||||
struct list_head suppliers;
|
||||
struct list_head consumers;
|
||||
struct list_head needs_suppliers;
|
||||
struct list_head defer_sync;
|
||||
struct list_head defer_hook;
|
||||
bool need_for_probe;
|
||||
enum dl_dev_state status;
|
||||
};
|
||||
@ -1377,6 +1350,36 @@ struct device {
|
||||
ANDROID_KABI_RESERVE(8);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct device_link - Device link representation.
|
||||
* @supplier: The device on the supplier end of the link.
|
||||
* @s_node: Hook to the supplier device's list of links to consumers.
|
||||
* @consumer: The device on the consumer end of the link.
|
||||
* @c_node: Hook to the consumer device's list of links to suppliers.
|
||||
* @link_dev: device used to expose link details in sysfs
|
||||
* @status: The state of the link (with respect to the presence of drivers).
|
||||
* @flags: Link flags.
|
||||
* @rpm_active: Whether or not the consumer device is runtime-PM-active.
|
||||
* @kref: Count repeated addition of the same link.
|
||||
* @rcu_head: An RCU head to use for deferred execution of SRCU callbacks.
|
||||
* @supplier_preactivated: Supplier has been made active before consumer probe.
|
||||
*/
|
||||
struct device_link {
|
||||
struct device *supplier;
|
||||
struct list_head s_node;
|
||||
struct device *consumer;
|
||||
struct list_head c_node;
|
||||
struct device link_dev;
|
||||
enum device_link_state status;
|
||||
u32 flags;
|
||||
refcount_t rpm_active;
|
||||
struct kref kref;
|
||||
#ifdef CONFIG_SRCU
|
||||
struct rcu_head rcu_head;
|
||||
#endif
|
||||
bool supplier_preactivated; /* Owned by consumer probe. */
|
||||
};
|
||||
|
||||
static inline struct device *kobj_to_dev(struct kobject *kobj)
|
||||
{
|
||||
return container_of(kobj, struct device, kobj);
|
||||
|
78
include/linux/prandom.h
Normal file
78
include/linux/prandom.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* include/linux/prandom.h
|
||||
*
|
||||
* Include file for the fast pseudo-random 32-bit
|
||||
* generation.
|
||||
*/
|
||||
#ifndef _LINUX_PRANDOM_H
|
||||
#define _LINUX_PRANDOM_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/percpu.h>
|
||||
|
||||
u32 prandom_u32(void);
|
||||
void prandom_bytes(void *buf, size_t nbytes);
|
||||
void prandom_seed(u32 seed);
|
||||
void prandom_reseed_late(void);
|
||||
|
||||
struct rnd_state {
|
||||
__u32 s1, s2, s3, s4;
|
||||
};
|
||||
|
||||
DECLARE_PER_CPU(struct rnd_state, net_rand_state);
|
||||
|
||||
u32 prandom_u32_state(struct rnd_state *state);
|
||||
void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
|
||||
void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
|
||||
|
||||
#define prandom_init_once(pcpu_state) \
|
||||
DO_ONCE(prandom_seed_full_state, (pcpu_state))
|
||||
|
||||
/**
|
||||
* prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro)
|
||||
* @ep_ro: right open interval endpoint
|
||||
*
|
||||
* Returns a pseudo-random number that is in interval [0, ep_ro). Note
|
||||
* that the result depends on PRNG being well distributed in [0, ~0U]
|
||||
* u32 space. Here we use maximally equidistributed combined Tausworthe
|
||||
* generator, that is, prandom_u32(). This is useful when requesting a
|
||||
* random index of an array containing ep_ro elements, for example.
|
||||
*
|
||||
* Returns: pseudo-random number in interval [0, ep_ro)
|
||||
*/
|
||||
static inline u32 prandom_u32_max(u32 ep_ro)
|
||||
{
|
||||
return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle minimum values for seeds
|
||||
*/
|
||||
static inline u32 __seed(u32 x, u32 m)
|
||||
{
|
||||
return (x < m) ? x + m : x;
|
||||
}
|
||||
|
||||
/**
|
||||
* prandom_seed_state - set seed for prandom_u32_state().
|
||||
* @state: pointer to state structure to receive the seed.
|
||||
* @seed: arbitrary 64-bit value to use as a seed.
|
||||
*/
|
||||
static inline void prandom_seed_state(struct rnd_state *state, u64 seed)
|
||||
{
|
||||
u32 i = (seed >> 32) ^ (seed << 10) ^ seed;
|
||||
|
||||
state->s1 = __seed(i, 2U);
|
||||
state->s2 = __seed(i, 8U);
|
||||
state->s3 = __seed(i, 16U);
|
||||
state->s4 = __seed(i, 128U);
|
||||
}
|
||||
|
||||
/* Pseudo random number generator from numerical recipes. */
|
||||
static inline u32 next_pseudo_random32(u32 seed)
|
||||
{
|
||||
return seed * 1664525 + 1013904223;
|
||||
}
|
||||
|
||||
#endif
|
@ -108,61 +108,12 @@ declare_get_random_var_wait(long)
|
||||
|
||||
unsigned long randomize_page(unsigned long start, unsigned long range);
|
||||
|
||||
u32 prandom_u32(void);
|
||||
void prandom_bytes(void *buf, size_t nbytes);
|
||||
void prandom_seed(u32 seed);
|
||||
void prandom_reseed_late(void);
|
||||
|
||||
struct rnd_state {
|
||||
__u32 s1, s2, s3, s4;
|
||||
};
|
||||
|
||||
u32 prandom_u32_state(struct rnd_state *state);
|
||||
void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
|
||||
void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
|
||||
|
||||
#define prandom_init_once(pcpu_state) \
|
||||
DO_ONCE(prandom_seed_full_state, (pcpu_state))
|
||||
|
||||
/**
|
||||
* prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro)
|
||||
* @ep_ro: right open interval endpoint
|
||||
*
|
||||
* Returns a pseudo-random number that is in interval [0, ep_ro). Note
|
||||
* that the result depends on PRNG being well distributed in [0, ~0U]
|
||||
* u32 space. Here we use maximally equidistributed combined Tausworthe
|
||||
* generator, that is, prandom_u32(). This is useful when requesting a
|
||||
* random index of an array containing ep_ro elements, for example.
|
||||
*
|
||||
* Returns: pseudo-random number in interval [0, ep_ro)
|
||||
*/
|
||||
static inline u32 prandom_u32_max(u32 ep_ro)
|
||||
{
|
||||
return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle minimum values for seeds
|
||||
* This is designed to be standalone for just prandom
|
||||
* users, but for now we include it from <linux/random.h>
|
||||
* for legacy reasons.
|
||||
*/
|
||||
static inline u32 __seed(u32 x, u32 m)
|
||||
{
|
||||
return (x < m) ? x + m : x;
|
||||
}
|
||||
|
||||
/**
|
||||
* prandom_seed_state - set seed for prandom_u32_state().
|
||||
* @state: pointer to state structure to receive the seed.
|
||||
* @seed: arbitrary 64-bit value to use as a seed.
|
||||
*/
|
||||
static inline void prandom_seed_state(struct rnd_state *state, u64 seed)
|
||||
{
|
||||
u32 i = (seed >> 32) ^ (seed << 10) ^ seed;
|
||||
|
||||
state->s1 = __seed(i, 2U);
|
||||
state->s2 = __seed(i, 8U);
|
||||
state->s3 = __seed(i, 16U);
|
||||
state->s4 = __seed(i, 128U);
|
||||
}
|
||||
#include <linux/prandom.h>
|
||||
|
||||
#ifdef CONFIG_ARCH_RANDOM
|
||||
# include <asm/archrandom.h>
|
||||
@ -185,10 +136,4 @@ static inline bool __must_check arch_get_random_seed_int(unsigned int *v)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Pseudo random number generator from numerical recipes. */
|
||||
static inline u32 next_pseudo_random32(u32 seed)
|
||||
{
|
||||
return seed * 1664525 + 1013904223;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_RANDOM_H */
|
||||
|
@ -450,6 +450,19 @@ static inline void psock_set_prog(struct bpf_prog **pprog,
|
||||
bpf_prog_put(prog);
|
||||
}
|
||||
|
||||
static inline int psock_replace_prog(struct bpf_prog **pprog,
|
||||
struct bpf_prog *prog,
|
||||
struct bpf_prog *old)
|
||||
{
|
||||
if (cmpxchg(pprog, old, prog) != old)
|
||||
return -ENOENT;
|
||||
|
||||
if (old)
|
||||
bpf_prog_put(old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void psock_progs_drop(struct sk_psock_progs *progs)
|
||||
{
|
||||
psock_set_prog(&progs->msg_parser, NULL);
|
||||
|
@ -2029,10 +2029,10 @@ static int bpf_prog_detach(const union bpf_attr *attr)
|
||||
ptype = BPF_PROG_TYPE_CGROUP_DEVICE;
|
||||
break;
|
||||
case BPF_SK_MSG_VERDICT:
|
||||
return sock_map_get_from_fd(attr, NULL);
|
||||
return sock_map_prog_detach(attr, BPF_PROG_TYPE_SK_MSG);
|
||||
case BPF_SK_SKB_STREAM_PARSER:
|
||||
case BPF_SK_SKB_STREAM_VERDICT:
|
||||
return sock_map_get_from_fd(attr, NULL);
|
||||
return sock_map_prog_detach(attr, BPF_PROG_TYPE_SK_SKB);
|
||||
case BPF_LIRC_MODE2:
|
||||
return lirc_prog_detach(attr);
|
||||
case BPF_FLOW_DISSECTOR:
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <linux/sched/debug.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
@ -1775,6 +1776,13 @@ void update_process_times(int user_tick)
|
||||
scheduler_tick();
|
||||
if (IS_ENABLED(CONFIG_POSIX_TIMERS))
|
||||
run_posix_cpu_timers();
|
||||
|
||||
/* The current CPU might make use of net randoms without receiving IRQs
|
||||
* to renew them often enough. Let's update the net_rand_state from a
|
||||
* non-constant value that's not affine to the number of calls to make
|
||||
* sure it's updated when there's some activity (we don't care in idle).
|
||||
*/
|
||||
this_cpu_add(net_rand_state.s1, rol32(jiffies, 24) + user_tick);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,7 @@ static inline void prandom_state_selftest(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static DEFINE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy;
|
||||
DEFINE_PER_CPU(struct rnd_state, net_rand_state);
|
||||
|
||||
/**
|
||||
* prandom_u32_state - seeded pseudo-random number generator.
|
||||
|
@ -71,7 +71,42 @@ int sock_map_get_from_fd(const union bpf_attr *attr, struct bpf_prog *prog)
|
||||
map = __bpf_map_get(f);
|
||||
if (IS_ERR(map))
|
||||
return PTR_ERR(map);
|
||||
ret = sock_map_prog_update(map, prog, attr->attach_type);
|
||||
ret = sock_map_prog_update(map, prog, NULL, attr->attach_type);
|
||||
fdput(f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sock_map_prog_detach(const union bpf_attr *attr, enum bpf_prog_type ptype)
|
||||
{
|
||||
u32 ufd = attr->target_fd;
|
||||
struct bpf_prog *prog;
|
||||
struct bpf_map *map;
|
||||
struct fd f;
|
||||
int ret;
|
||||
|
||||
if (attr->attach_flags)
|
||||
return -EINVAL;
|
||||
|
||||
f = fdget(ufd);
|
||||
map = __bpf_map_get(f);
|
||||
if (IS_ERR(map))
|
||||
return PTR_ERR(map);
|
||||
|
||||
prog = bpf_prog_get(attr->attach_bpf_fd);
|
||||
if (IS_ERR(prog)) {
|
||||
ret = PTR_ERR(prog);
|
||||
goto put_map;
|
||||
}
|
||||
|
||||
if (prog->type != ptype) {
|
||||
ret = -EINVAL;
|
||||
goto put_prog;
|
||||
}
|
||||
|
||||
ret = sock_map_prog_update(map, NULL, prog, attr->attach_type);
|
||||
put_prog:
|
||||
bpf_prog_put(prog);
|
||||
put_map:
|
||||
fdput(f);
|
||||
return ret;
|
||||
}
|
||||
@ -1015,27 +1050,32 @@ static struct sk_psock_progs *sock_map_progs(struct bpf_map *map)
|
||||
}
|
||||
|
||||
int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog,
|
||||
u32 which)
|
||||
struct bpf_prog *old, u32 which)
|
||||
{
|
||||
struct sk_psock_progs *progs = sock_map_progs(map);
|
||||
struct bpf_prog **pprog;
|
||||
|
||||
if (!progs)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (which) {
|
||||
case BPF_SK_MSG_VERDICT:
|
||||
psock_set_prog(&progs->msg_parser, prog);
|
||||
pprog = &progs->msg_parser;
|
||||
break;
|
||||
case BPF_SK_SKB_STREAM_PARSER:
|
||||
psock_set_prog(&progs->skb_parser, prog);
|
||||
pprog = &progs->skb_parser;
|
||||
break;
|
||||
case BPF_SK_SKB_STREAM_VERDICT:
|
||||
psock_set_prog(&progs->skb_verdict, prog);
|
||||
pprog = &progs->skb_verdict;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (old)
|
||||
return psock_replace_prog(pprog, prog, old);
|
||||
|
||||
psock_set_prog(pprog, prog);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -793,19 +793,19 @@ static void test_sockmap(unsigned int tasks, void *data)
|
||||
}
|
||||
|
||||
err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER);
|
||||
if (err) {
|
||||
if (!err) {
|
||||
printf("Failed empty parser prog detach\n");
|
||||
goto out_sockmap;
|
||||
}
|
||||
|
||||
err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT);
|
||||
if (err) {
|
||||
if (!err) {
|
||||
printf("Failed empty verdict prog detach\n");
|
||||
goto out_sockmap;
|
||||
}
|
||||
|
||||
err = bpf_prog_detach(fd, BPF_SK_MSG_VERDICT);
|
||||
if (err) {
|
||||
if (!err) {
|
||||
printf("Failed empty msg verdict prog detach\n");
|
||||
goto out_sockmap;
|
||||
}
|
||||
@ -1094,19 +1094,19 @@ static void test_sockmap(unsigned int tasks, void *data)
|
||||
assert(status == 0);
|
||||
}
|
||||
|
||||
err = bpf_prog_detach(map_fd_rx, __MAX_BPF_ATTACH_TYPE);
|
||||
err = bpf_prog_detach2(parse_prog, map_fd_rx, __MAX_BPF_ATTACH_TYPE);
|
||||
if (!err) {
|
||||
printf("Detached an invalid prog type.\n");
|
||||
goto out_sockmap;
|
||||
}
|
||||
|
||||
err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_PARSER);
|
||||
err = bpf_prog_detach2(parse_prog, map_fd_rx, BPF_SK_SKB_STREAM_PARSER);
|
||||
if (err) {
|
||||
printf("Failed parser prog detach\n");
|
||||
goto out_sockmap;
|
||||
}
|
||||
|
||||
err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_VERDICT);
|
||||
err = bpf_prog_detach2(verdict_prog, map_fd_rx, BPF_SK_SKB_STREAM_VERDICT);
|
||||
if (err) {
|
||||
printf("Failed parser prog detach\n");
|
||||
goto out_sockmap;
|
||||
|
Loading…
Reference in New Issue
Block a user