5.8.17-rc1 review
Subsystems (3)
Greg Kroah-Hartman
maintainerPATCH 318/633 mm, oom_adj: dont loop through tasks in __set_oom_adj when not necessary
In reply to Greg Kroah-HartmanFrom: Suren Baghdasaryan <[email protected]>
[ Upstream commit 67197a4f28d28d0b073ab0427b03cb2ee5382578 ]
Currently __set_oom_adj loops through all processes in the system to keep oom_score_adj and oom_score_adj_min in sync between processes sharing their mm. This is done for any task with more that one mm_users, which includes processes with multiple threads (sharing mm and signals). However for such processes the loop is unnecessary because their signal structure is shared as well.
Android updates oom_score_adj whenever a tasks changes its role (background/foreground/...) or binds to/unbinds from a service, making it more/less important. Such operation can happen frequently. We noticed that updates to oom_score_adj became more expensive and after further investigation found out that the patch mentioned in "Fixes" introduced a regression. Using Pixel 4 with a typical Android workload, write time to oom_score_adj increased from ~3.57us to ~362us. Moreover this regression linearly depends on the number of multi-threaded processes running on the system.
Mark the mm with a new MMF_MULTIPROCESS flag bit when task is created with (CLONE_VM && !CLONE_THREAD && !CLONE_VFORK). Change __set_oom_adj to use MMF_MULTIPROCESS instead of mm_users to decide whether oom_score_adj update should be synchronized between multiple processes. To prevent races between clone() and __set_oom_adj(), when oom_score_adj of the process being cloned might be modified from userspace, we use oom_adj_mutex. Its scope is changed to global.
The combination of (CLONE_VM && !CLONE_THREAD) is rarely used except for the case of vfork(). To prevent performance regressions of vfork(), we skip taking oom_adj_mutex and setting MMF_MULTIPROCESS when CLONE_VFORK is specified. Clearing the MMF_MULTIPROCESS flag (when the last process sharing the mm exits) is left out of this patch to keep it simple and because it is believed that this threading model is rare. Should there ever be a need for optimizing that case as well, it can be done by hooking into the exit path, likely following the mm_update_next_owner pattern.
With the combination of (CLONE_VM && !CLONE_THREAD && !CLONE_VFORK) being quite rare, the regression is gone after the change is applied.
--- fs/proc/base.c | 3 +-- include/linux/oom.h | 1 + include/linux/sched/coredump.h | 1 + kernel/fork.c | 21 +++++++++++++++++++++ mm/oom_kill.c | 2 ++ 5 files changed, 26 insertions(+), 2 deletions(-)
fs/proc/base.c +1 -2
@@ -1046,7 +1046,6 @@ static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,static int __set_oom_adj (struct file *file,int oom_adj,bool legacy) { -static DEFINE_MUTEX (oom_adj_mutex);struct mm_struct *mm =NULL ;struct task_struct *task;int err =0 ;
@@ -1086,7 +1085,7 @@ static int __set_oom_adj(struct file *file, int oom_adj, bool legacy)struct task_struct *p =find_lock_task_mm (task);if (p) { -if (atomic_read (&p->mm->mm_users) >1 ) { +if (test_bit (MMF_MULTIPROCESS , &p->mm->flags)) { mm = p->mm;mmgrab (mm); }
include/linux/oom.h +1 -0
@@ -55,6 +55,7 @@ struct oom_control { };extern struct mutex oom_lock; +extern struct mutex oom_adj_mutex;static inline void set_current_oom_origin (void ) {
include/linux/sched/coredump.h +1 -0
@@ -72,6 +72,7 @@ static inline int get_dumpable(struct mm_struct *mm)#define MMF_DISABLE_THP 24/* disable THP for all VMAs */ #define MMF_OOM_VICTIM 25/* mm is the oom victim */ #define MMF_OOM_REAP_QUEUED 26/* mm was queued for oom_reaper */ +#define MMF_MULTIPROCESS 27/* mm is shared between processes */ #define MMF_DISABLE_THP_MASK (1 << MMF_DISABLE_THP)#define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK |\
kernel/fork.c +21 -0
@@ -1830,6 +1830,25 @@ static __always_inline void delayed_free_task(struct task_struct *tsk)free_task (tsk); } +static void copy_oom_score_adj (u64 clone_flags,struct task_struct *tsk) +{ +/* Skip if kernel thread */ +if (!tsk->mm) +return ; + +/* Skip if spawning a thread or using vfork */ +if ((clone_flags & (CLONE_VM |CLONE_THREAD |CLONE_VFORK )) !=CLONE_VM ) +return ; + +/* We need to synchronize with __set_oom_adj */ +mutex_lock (&oom_adj_mutex); +set_bit (MMF_MULTIPROCESS , &tsk->mm->flags); +/* Update the values in case they were changed after copy_signal */ + tsk->signal->oom_score_adj = current->signal->oom_score_adj; + tsk->signal->oom_score_adj_min = current->signal->oom_score_adj_min; +mutex_unlock (&oom_adj_mutex); +} +/* * This creates a new process as a copy of the old one, * but does not actually start it yet.
@@ -2310,6 +2329,8 @@ static __latent_entropy struct task_struct *copy_process(trace_task_newtask (p, clone_flags);uprobe_copy_process (p, clone_flags); +copy_oom_score_adj (clone_flags, p); +return p; bad_fork_cancel_cgroup:
mm/oom_kill.c +2 -0
@@ -64,6 +64,8 @@ int sysctl_oom_dump_tasks = 1;* and mark_oom_victim */ DEFINE_MUTEX (oom_lock); +/* Serializes oom_score_adj and oom_score_adj_min updates */ +DEFINE_MUTEX (oom_adj_mutex);static inline bool is_memcg_oom (struct oom_control *oc) {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 319/633 fs: fix NULL dereference due to data race in prepend_path()
In reply to Greg Kroah-HartmanFrom: Andrii Nakryiko <[email protected]>
[ Upstream commit 09cad07547445bf3a41683e4d3abcd154c123ef5 ]
Fix data race in prepend_path() with re-reading mnt->mnt_ns twice without holding the lock.
is_mounted() does check for NULL, but is_anon_ns(mnt->mnt_ns) might re-read the pointer again which could be NULL already, if in between reads one of kern_unmount()/kern_unmount_array()/umount_tree() sets mnt->mnt_ns to NULL.
This is seen in production with the following stack trace:
BUG: kernel NULL pointer dereference, address: 0000000000000048
...
RIP: 0010:prepend_path.isra.4+0x1ce/0x2e0
Call Trace:
d_path+0xe6/0x150
proc_pid_readlink+0x8f/0x100
vfs_readlink+0xf8/0x110
do_readlinkat+0xfd/0x120
__x64_sys_readlinkat+0x1a/0x20
do_syscall_64+0x42/0x110
entry_SYSCALL_64_after_hwframe+0x44/0xa9--- fs/d_path.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/d_path.c +5 -1
@@ -102,6 +102,8 @@ static int prepend_path(const struct path *path,if (dentry == vfsmnt->mnt_root ||IS_ROOT (dentry)) {struct mount *parent =READ_ONCE (mnt->mnt_parent); +struct mnt_namespace *mnt_ns; +/* Escaped? */ if (dentry != vfsmnt->mnt_root) { bptr = *buffer;
@@ -116,7 +118,9 @@ static int prepend_path(const struct path *path, vfsmnt = &mnt->mnt;continue ; } -if (is_mounted (vfsmnt) && !is_anon_ns (mnt->mnt_ns)) + mnt_ns =READ_ONCE (mnt->mnt_ns); +/* open-coded is_mounted() to use local mnt_ns */ +if (!IS_ERR_OR_NULL (mnt_ns) && !is_anon_ns (mnt_ns)) error =1 ;// absolute root else error =2 ;// detached or not attached yet
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 320/633 selftests/ftrace: Change synthetic event name for inter-event-combined test
In reply to Greg Kroah-HartmanFrom: Tom Zanussi <[email protected]>
[ Upstream commit 96378b2088faea68f1fb05ea6b9a566fc569a44c ]
This test uses waking+wakeup_latency as an event name, which doesn't make sense since it includes an operator. Illegal names are now detected by the synthetic event command parsing, which causes this test to fail. Change the name to 'waking_plus_wakeup_latency' to prevent this.
--- .../inter-event/trigger-inter-event-combined-hist.tc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc +4 -4
@@ -25,12 +25,12 @@ echo 'wakeup_latency u64 lat pid_t pid' >> synthetic_events echo 'hist:keys=pid:ts1=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_wakeup/trigger echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts1:onmatch(sched.sched_wakeup).wakeup_latency($wakeup_lat,next_pid) if next_comm=="ping"' > events/sched/sched_switch/trigger -echo 'waking+wakeup_latency u64 lat; pid_t pid' >> synthetic_events -echo 'hist:keys=pid,lat:sort=pid,lat:ww_lat=$waking_lat+$wakeup_lat:onmatch(synthetic.wakeup_latency).waking+wakeup_latency($ww_lat,pid)' >> events/synthetic/wakeup_latency/trigger -echo 'hist:keys=pid,lat:sort=pid,lat' >> events/synthetic/waking+wakeup_latency/trigger +echo 'waking_plus_wakeup_latency u64 lat; pid_t pid' >> synthetic_events +echo 'hist:keys=pid,lat:sort=pid,lat:ww_lat=$waking_lat+$wakeup_lat:onmatch(synthetic.wakeup_latency).waking_plus_wakeup_latency($ww_lat,pid)' >> events/synthetic/wakeup_latency/trigger +echo 'hist:keys=pid,lat:sort=pid,lat' >> events/synthetic/waking_plus_wakeup_latency/trigger ping $LOCALHOST -c 3 -if ! grep -q "pid:" events/synthetic/waking+wakeup_latency/hist; then +if ! grep -q "pid:" events/synthetic/waking_plus_wakeup_latency/hist; then fail "Failed to create combined histogram" fi
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 321/633 tracing: Handle synthetic event array field type checking correctly
In reply to Greg Kroah-HartmanFrom: Tom Zanussi <[email protected]>
[ Upstream commit 10819e25799aae564005b6049a45e9808797b3bb ]
Since synthetic event array types are derived from the field name, there may be a semicolon at the end of the type which should be stripped off.
If there are more characters following that, normal type string checking will result in an invalid type.
Without this patch, you can end up with an invalid field type string that gets displayed in both the synthetic event description and the event format:
Before:
# echo 'myevent char str[16]; int v' >> synthetic_events
# cat synthetic_events
myevent char[16]; str; int v name: myevent
ID: 1936
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:char str[16];; offset:8; size:16; signed:1; field:int v; offset:40; size:4; signed:1;
print fmt: "str=%s, v=%d", REC->str, REC->v
After:
# echo 'myevent char str[16]; int v' >> synthetic_events
# cat synthetic_events
myevent char[16] str; int v# cat events/synthetic/myevent/format name: myevent ID: 1936 format: field:unsigned short common_type; offset:0; size:2; signed:0; field:unsigned char common_flags; offset:2; size:1; signed:0; field:unsigned char common_preempt_count; offset:3; size:1; signed:0; field:int common_pid; offset:4; size:4; signed:1;
field:char str[16]; offset:8; size:16; signed:1; field:int v; offset:40; size:4; signed:1;
print fmt: "str=%s, v=%d", REC->str, REC->v
--- kernel/trace/trace_events_synth.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
kernel/trace/trace_events_synth.c +9 -3
@@ -132,7 +132,7 @@ static int synth_field_string_size(char *type) start +=sizeof ("char[" ) -1 ; end =strchr (type,']' ); -if (!end || end < start) +if (!end || end < start || type +strlen (type) > end +1 )return -EINVAL ; len = end - start;
@@ -502,8 +502,14 @@ static struct synth_field *parse_synth_field(int argc, const char **argv,if (field_type[0 ] ==';' ) field_type++; len =strlen (field_type) +1 ; -if (array) - len +=strlen (array); + +if (array) { +int l =strlen (array); + +if (l && array[l -1 ] ==';' ) + l--; + len += l; + }if (prefix) len +=strlen (prefix);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 322/633 i3c: master add i3c_master_attach_boardinfo to preserve boardinfo
In reply to Greg Kroah-HartmanFrom: Parshuram Thombare <[email protected]>
[ Upstream commit 9da36a7ec42135428e1d41621e3703429bda3b2e ]
Boardinfo was lost if I3C object for devices with boardinfo available are not created or not added to the I3C device list because of some failure e.g. SETDASA failed, retrieve info failed etc This patch adds i3c_master_attach_boardinfo which scan boardinfo list in the master object and 'attach' it to the I3C device object.
--- drivers/i3c/master.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
drivers/i3c/master.c +17 -2
@@ -1782,6 +1782,21 @@ static void i3c_master_bus_cleanup(struct i3c_master_controller *master)i3c_master_detach_free_devs (master); } +static void i3c_master_attach_boardinfo (struct i3c_dev_desc *i3cdev) +{ +struct i3c_master_controller *master = i3cdev->common.master; +struct i3c_dev_boardinfo *i3cboardinfo; + +list_for_each_entry (i3cboardinfo, &master->boardinfo.i3c, node) { +if (i3cdev->info.pid != i3cboardinfo->pid) +continue ; + + i3cdev->boardinfo = i3cboardinfo; + i3cdev->info.static_addr = i3cboardinfo->static_addr; +return ; + } +} +static struct i3c_dev_desc *i3c_master_search_i3c_dev_duplicate (struct i3c_dev_desc *refdev) {
@@ -1837,10 +1852,10 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,if (ret) goto err_detach_dev; +i3c_master_attach_boardinfo (newdev); + olddev =i3c_master_search_i3c_dev_duplicate (newdev);if (olddev) { - newdev->boardinfo = olddev->boardinfo; - newdev->info.static_addr = olddev->info.static_addr; newdev->dev = olddev->dev;if (newdev->dev) newdev->dev->desc = newdev;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 323/633 IB/mlx4: Fix starvation in paravirt mux/demux
In reply to Greg Kroah-HartmanFrom: Håkon Bugge <[email protected]>
[ Upstream commit 7fd1507df7cee9c533f38152fcd1dd769fcac6ce ]
The mlx4 driver will proxy MAD packets through the PF driver. A VM or an instantiated VF will send its MAD packets to the PF driver using loop-back. The PF driver will be informed by an interrupt, but defer the handling and polling of CQEs to a worker thread running on an ordered work-queue.
Consider the following scenario: the VMs will in short proximity in time, for example due to a network event, send many MAD packets to the PF driver. Lets say there are K VMs, each sending N packets.
The interrupt from the first VM will start the worker thread, which will poll N CQEs. A common case here is where the PF driver will multiplex the packets received from the VMs out on the wire QP.
But before the wire QP has returned a send CQE and associated interrupt, the other K - 1 VMs have sent their N packets as well.
The PF driver has to multiplex K * N packets out on the wire QP. But the send-queue on the wire QP has a finite capacity.
So, in this scenario, if K * N is larger than the send-queue capacity of the wire QP, we will get MAD packets dropped on the floor with this dynamic debug message:
mlx4_ib_multiplex_mad: failed sending GSI to wire on behalf of slave 2 (-11)
and this despite the fact that the wire send-queue could have capacity, but the PF driver isn't aware, because the wire send CQEs have not yet been polled.
We can also have a similar scenario inbound, with a wire recv-queue larger than the tunnel QP's send-queue. If many remote peers send MAD packets to the very same VM, the tunnel send-queue destined to the VM could allegedly be construed to be full by the PF driver.
This starvation is fixed by introducing separate work queues for the wire QPs vs. the tunnel QPs.
With this fix, using a dual ported HCA, 8 VFs instantiated, we could run cmtime on each of the 18 interfaces towards a similar configured peer, each cmtime instance with 800 QPs (all in all 14400 QPs) without a single CM packet getting lost.
--- drivers/infiniband/hw/mlx4/mad.c | 34 +++++++++++++++++++++++++--- drivers/infiniband/hw/mlx4/mlx4_ib.h | 2 ++ 2 files changed, 33 insertions(+), 3 deletions(-)
drivers/infiniband/hw/mlx4/mad.c +31 -3
@@ -1299,6 +1299,18 @@ static void mlx4_ib_tunnel_comp_handler(struct ib_cq *cq, void *arg)spin_unlock_irqrestore (&dev->sriov.going_down_lock, flags); } +static void mlx4_ib_wire_comp_handler (struct ib_cq *cq,void *arg) +{ +unsigned long flags; +struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; +struct mlx4_ib_dev *dev =to_mdev (ctx->ib_dev); + +spin_lock_irqsave (&dev->sriov.going_down_lock, flags); +if (!dev->sriov.is_going_down && ctx->state ==DEMUX_PV_STATE_ACTIVE ) +queue_work (ctx->wi_wq, &ctx->work); +spin_unlock_irqrestore (&dev->sriov.going_down_lock, flags); +} +static int mlx4_ib_post_pv_qp_buf (struct mlx4_ib_demux_pv_ctx *ctx,struct mlx4_ib_demux_pv_qp *tun_qp,int index)
@@ -2001,7 +2013,8 @@ static int create_pv_resources(struct ib_device *ibdev, int slave, int port, cq_size *=2 ; cq_attr.cqe = cq_size; - ctx->cq =ib_create_cq (ctx->ib_dev, mlx4_ib_tunnel_comp_handler, + ctx->cq =ib_create_cq (ctx->ib_dev, + create_tun ? mlx4_ib_tunnel_comp_handler : mlx4_ib_wire_comp_handler,NULL , ctx, &cq_attr);if (IS_ERR (ctx->cq)) { ret =PTR_ERR (ctx->cq);
@@ -2038,6 +2051,7 @@ static int create_pv_resources(struct ib_device *ibdev, int slave, int port,INIT_WORK (&ctx->work, mlx4_ib_sqp_comp_worker); ctx->wq =to_mdev (ibdev)->sriov.demux[port -1 ].wq; + ctx->wi_wq =to_mdev (ibdev)->sriov.demux[port -1 ].wi_wq; ret =ib_req_notify_cq (ctx->cq,IB_CQ_NEXT_COMP );if (ret) {
@@ -2181,7 +2195,7 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev, goto err_mcg; } -snprintf (name,sizeof name,"mlx4_ibt%d" , port); +snprintf (name,sizeof (name),"mlx4_ibt%d" , port); ctx->wq =alloc_ordered_workqueue (name,WQ_MEM_RECLAIM );if (!ctx->wq) {pr_err ("Failed to create tunnelling WQ for port %d\n" , port);
@@ -2189,7 +2203,15 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev, goto err_wq; } -snprintf (name,sizeof name,"mlx4_ibud%d" , port); +snprintf (name,sizeof (name),"mlx4_ibwi%d" , port); + ctx->wi_wq =alloc_ordered_workqueue (name,WQ_MEM_RECLAIM ); +if (!ctx->wi_wq) { +pr_err ("Failed to create wire WQ for port %d\n" , port); + ret = -ENOMEM ; + goto err_wiwq; + } + +snprintf (name,sizeof (name),"mlx4_ibud%d" , port); ctx->ud_wq =alloc_ordered_workqueue (name,WQ_MEM_RECLAIM );if (!ctx->ud_wq) {pr_err ("Failed to create up/down WQ for port %d\n" , port);
@@ -2200,6 +2222,10 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,return 0 ; err_udwq: +destroy_workqueue (ctx->wi_wq); + ctx->wi_wq =NULL ; + +err_wiwq:destroy_workqueue (ctx->wq); ctx->wq =NULL ;
@@ -2247,12 +2273,14 @@ static void mlx4_ib_free_demux_ctx(struct mlx4_ib_demux_ctx *ctx) ctx->tun[i]->state =DEMUX_PV_STATE_DOWNING ; }flush_workqueue (ctx->wq); +flush_workqueue (ctx->wi_wq);for (i =0 ; i < dev->dev->caps.sqp_demux; i++) {destroy_pv_resources (dev, i, ctx->port, ctx->tun[i],0 );free_pv_object (dev, i, ctx->port); }kfree (ctx->tun);destroy_workqueue (ctx->ud_wq); +destroy_workqueue (ctx->wi_wq);destroy_workqueue (ctx->wq); } }
drivers/infiniband/hw/mlx4/mlx4_ib.h +2 -0
@@ -454,6 +454,7 @@ struct mlx4_ib_demux_pv_ctx {struct ib_pd *pd;struct work_struct work;struct workqueue_struct *wq; +struct workqueue_struct *wi_wq;struct mlx4_ib_demux_pv_qp qp[2 ]; };
@@ -461,6 +462,7 @@ struct mlx4_ib_demux_ctx {struct ib_device *ib_dev;int port;struct workqueue_struct *wq; +struct workqueue_struct *wi_wq;struct workqueue_struct *ud_wq;spinlock_t ud_lock;atomic64_t subnet_prefix;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 324/633 IB/mlx4: Adjust delayed work when a dup is observed
In reply to Greg Kroah-HartmanFrom: Håkon Bugge <[email protected]>
[ Upstream commit 785167a114855c5aa75efca97000e405c2cc85bf ]
When scheduling delayed work to clean up the cache, if the entry already has been scheduled for deletion, we adjust the delay.
--- drivers/infiniband/hw/mlx4/cm.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/infiniband/hw/mlx4/cm.c +3 -0
@@ -280,6 +280,9 @@ static void schedule_delayed(struct ib_device *ibdev, struct id_map_entry *id)if (!sriov->is_going_down && !id->scheduled_delete) { id->scheduled_delete =1 ;schedule_delayed_work (&id->timeout,CM_CLEANUP_CACHE_TIMEOUT ); + }else if (id->scheduled_delete) { +/* Adjust timeout if already scheduled */ +mod_delayed_work (system_wq, &id->timeout,CM_CLEANUP_CACHE_TIMEOUT ); }spin_unlock_irqrestore (&sriov->going_down_lock, flags);spin_unlock (&sriov->id_map_lock);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 325/633 powerpc/pseries: Fix missing of_node_put() in rng_init()
In reply to Greg Kroah-HartmanFrom: Nicholas Mc Guire <[email protected]>
[ Upstream commit 67c3e59443f5fc77be39e2ce0db75fbfa78c7965 ]
The call to of_find_compatible_node() returns a node pointer with refcount incremented thus it must be explicitly decremented here before returning.
--- arch/powerpc/platforms/pseries/rng.c | 1 + 1 file changed, 1 insertion(+)
arch/powerpc/platforms/pseries/rng.c +1 -0
@@ -36,6 +36,7 @@ static __init int rng_init(void) ppc_md.get_random_seed = pseries_get_random_long; +of_node_put (dn);return 0 ; }machine_subsys_initcall (pseries, rng_init);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 326/633 powerpc/icp-hv: Fix missing of_node_put() in success path
In reply to Greg Kroah-HartmanFrom: Nicholas Mc Guire <[email protected]>
[ Upstream commit d3e669f31ec35856f5e85df9224ede5bdbf1bc7b ]
Both of_find_compatible_node() and of_find_node_by_type() will return a refcounted node on success - thus for the success path the node must be explicitly released with a of_node_put().
--- arch/powerpc/sysdev/xics/icp-hv.c | 1 + 1 file changed, 1 insertion(+)
arch/powerpc/sysdev/xics/icp-hv.c +1 -0
@@ -174,6 +174,7 @@ int icp_hv_init(void) icp_ops = &icp_hv_ops; +of_node_put (np);return 0 ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 327/633 rcu/tree: Force quiescent state on callback overload
In reply to Greg Kroah-HartmanFrom: Neeraj Upadhyay <[email protected]>
[ Upstream commit 9c39245382de4d52a122641952900709d4a9950b ]
On callback overload, it is necessary to quickly detect idle CPUs, and rcu_gp_fqs_check_wake() checks for this condition. Unfortunately, the code following the call to this function does not repeat this check, which means that in reality no actual quiescent-state forcing, instead only a couple of quick and pointless wakeups at the beginning of the grace period.
This commit therefore adds a check for the RCU_GP_FLAG_OVLD flag in the post-wakeup "if" statement in rcu_gp_fqs_loop().
--- kernel/rcu/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/rcu/tree.c +1 -1
@@ -1882,7 +1882,7 @@ static void rcu_gp_fqs_loop(void)break ;/* If time for quiescent-state forcing, do it. */ if (!time_after (rcu_state.jiffies_force_qs, jiffies) || - (gf &RCU_GP_FLAG_FQS )) { + (gf & (RCU_GP_FLAG_FQS |RCU_GP_FLAG_OVLD ))) {trace_rcu_grace_period (rcu_state.name, rcu_state.gp_seq,TPS ("fqsstart" ));rcu_gp_fqs (first_gp_fqs);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 328/633 rcutorture: Properly set rcu_fwds for OOM handling
In reply to Greg Kroah-HartmanFrom: Paul E. McKenney <[email protected]>
[ Upstream commit c8fa63714763b7795a3f5fb7ed6d000763e6dccc ]
The conversion of rcu_fwds to dynamic allocation failed to actually allocate the required structure. This commit therefore allocates it, frees it, and updates rcu_fwds accordingly. While in the area, it abstracts the cleanup actions into rcu_torture_fwd_prog_cleanup().
--- kernel/rcu/rcutorture.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
kernel/rcu/rcutorture.c +12 -1
@@ -2154,9 +2154,20 @@ static int __init rcu_torture_fwd_prog_init(void)return -ENOMEM ;spin_lock_init (&rfp->rcu_fwd_lock); rfp->rcu_fwd_cb_tail = &rfp->rcu_fwd_cb_head; + rcu_fwds = rfp;return torture_create_kthread (rcu_torture_fwd_prog, rfp, fwd_prog_task); } +static void rcu_torture_fwd_prog_cleanup (void ) +{ +struct rcu_fwd *rfp; + +torture_stop_kthread (rcu_torture_fwd_prog, fwd_prog_task); + rfp = rcu_fwds; + rcu_fwds =NULL ; +kfree (rfp); +} +/* Callback function for RCU barrier testing. */ static void rcu_torture_barrier_cbf (struct rcu_head *rcu) {
@@ -2360,7 +2371,7 @@ rcu_torture_cleanup(void)show_rcu_gp_kthreads ();rcu_torture_barrier_cleanup (); -torture_stop_kthread (rcu_torture_fwd_prog, fwd_prog_task); +rcu_torture_fwd_prog_cleanup ();torture_stop_kthread (rcu_torture_stall, stall_task);torture_stop_kthread (rcu_torture_writer, writer_task);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 329/633 RDMA/ucma: Fix locking for ctx->events_reported
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 98837c6c3d7285f6eca86480b6f7fac6880e27a8 ]
This value is locked under the file->mut, ensure it is held whenever touching it.
The case in ucma_migrate_id() is a race, while in ucma_free_uctx() it is already not possible for the write side to run, the movement is just for clarity.
--- drivers/infiniband/core/ucma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/infiniband/core/ucma.c +3 -1
@@ -586,6 +586,7 @@ static int ucma_free_ctx(struct ucma_context *ctx)list_move_tail (&uevent->list, &list); }list_del (&ctx->list); + events_reported = ctx->events_reported;mutex_unlock (&ctx->file->mut);list_for_each_entry_safe (uevent, tmp, &list, list) {
@@ -595,7 +596,6 @@ static int ucma_free_ctx(struct ucma_context *ctx)kfree (uevent); } - events_reported = ctx->events_reported;mutex_destroy (&ctx->mutex);kfree (ctx);return events_reported;
@@ -1678,7 +1678,9 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file, cur_file = ctx->file;if (cur_file == new_file) { +mutex_lock (&cur_file->mut); resp.events_reported = ctx->events_reported; +mutex_unlock (&cur_file->mut); goto response; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 330/633 RDMA/ucma: Add missing locking around rdma_leave_multicast()
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 38e03d092699891c3237b5aee9e8029d4ede0956 ]
All entry points to the rdma_cm from a ULP must be single threaded, even this error unwinds. Add the missing locking.
--- drivers/infiniband/core/ucma.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/infiniband/core/ucma.c +2 -0
@@ -1512,7 +1512,9 @@ static ssize_t ucma_process_join(struct ucma_file *file,return 0 ; err3: +mutex_lock (&ctx->mutex);rdma_leave_multicast (ctx->cm_id, (struct sockaddr *) &mc->addr); +mutex_unlock (&ctx->mutex);ucma_cleanup_mc_events (mc); err2:xa_erase (&multicast_table, mc->id);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 331/633 mtd: lpddr: fix excessive stack usage with clang
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
[ Upstream commit 3e1b6469f8324bee5927b063e2aca30d3e56b907 ]
Building lpddr2_nvm with clang can result in a giant stack usage in one function:
drivers/mtd/lpddr/lpddr2_nvm.c:399:12: error: stack frame size of 1144 bytes in function 'lpddr2_nvm_probe' [-Werror,-Wframe-larger-than=]
The problem is that clang decides to build a copy of the mtd_info structure on the stack and then do a memcpy() into the actual version. It shouldn't really do it that way, but it's not strictly a bug either.
As a workaround, use a static const version of the structure to assign most of the members upfront and then only set the few members that require runtime knowledge at probe time.
--- drivers/mtd/lpddr/lpddr2_nvm.c | 35 ++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-)
drivers/mtd/lpddr/lpddr2_nvm.c +19 -16
@@ -393,6 +393,17 @@ static int lpddr2_nvm_lock(struct mtd_info *mtd, loff_t start_add,return lpddr2_nvm_do_block_op (mtd, start_add, len,LPDDR2_NVM_LOCK ); } +static const struct mtd_info lpddr2_nvm_mtd_info = { + .type =MTD_RAM , + .writesize =1 , + .flags = (MTD_CAP_NVRAM |MTD_POWERUP_LOCK ), + ._read = lpddr2_nvm_read, + ._write = lpddr2_nvm_write, + ._erase = lpddr2_nvm_erase, + ._unlock = lpddr2_nvm_unlock, + ._lock = lpddr2_nvm_lock, +}; +/* * lpddr2_nvm driver probe method */
@@ -433,6 +444,7 @@ static int lpddr2_nvm_probe(struct platform_device *pdev) .pfow_base = OW_BASE_ADDRESS, .fldrv_priv = pcm_data, }; +if (IS_ERR (map->virt))return PTR_ERR (map->virt);
@@ -444,22 +456,13 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)return PTR_ERR (pcm_data->ctl_regs);/* Populate mtd_info data structure */ - *mtd = (struct mtd_info ) { - .dev = { .parent = &pdev->dev }, - .name = pdev->dev.init_name, - .type =MTD_RAM , - .priv = map, - .size =resource_size (add_range), - .erasesize =ERASE_BLOCKSIZE * pcm_data->bus_width, - .writesize =1 , - .writebufsize =WRITE_BUFFSIZE * pcm_data->bus_width, - .flags = (MTD_CAP_NVRAM |MTD_POWERUP_LOCK ), - ._read = lpddr2_nvm_read, - ._write = lpddr2_nvm_write, - ._erase = lpddr2_nvm_erase, - ._unlock = lpddr2_nvm_unlock, - ._lock = lpddr2_nvm_lock, - }; + *mtd = lpddr2_nvm_mtd_info; + mtd->dev.parent = &pdev->dev; + mtd->name = pdev->dev.init_name; + mtd->priv = map; + mtd->size =resource_size (add_range); + mtd->erasesize =ERASE_BLOCKSIZE * pcm_data->bus_width; + mtd->writebufsize =WRITE_BUFFSIZE * pcm_data->bus_width;/* Verify the presence of the device looking for PFOW string */ if (!lpddr2_nvm_pfow_present (map)) {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 332/633 RDMA/hns: Add a check for current state before modifying QP
In reply to Greg Kroah-HartmanFrom: Lang Cheng <[email protected]>
[ Upstream commit e0ef0f68c4c0d85b1eb63f38d5d10324361280e8 ]
It should be considered an illegal operation if the ULP attempts to modify a QP from another state to the current hardware state. Otherwise, the ULP can modify some fields of QPC at any time. For example, for a QP in state of RTS, modify it from RTR to RTS can change the PSN, which is always not as expected.
--- drivers/infiniband/hw/hns/hns_roce_qp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/infiniband/hw/hns/hns_roce_qp.c +4 -2
@@ -1171,8 +1171,10 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,mutex_lock (&hr_qp->mutex); - cur_state = attr_mask &IB_QP_CUR_STATE ? - attr->cur_qp_state : (enum ib_qp_state )hr_qp->state; +if (attr_mask &IB_QP_CUR_STATE && attr->cur_qp_state != hr_qp->state) + goto out; + + cur_state = hr_qp->state; new_state = attr_mask &IB_QP_STATE ? attr->qp_state : cur_state; if (ibqp->uobject &&
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 333/633 RDMA/umem: Fix signature of stub ib_umem_find_best_pgsz()
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 61690d01db32eb1f94adc9ac2b8bb741d34e4671 ]
The original function returns unsigned long and 0 on failure.
--- include/rdma/ib_umem.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
include/rdma/ib_umem.h +5 -4
@@ -95,10 +95,11 @@ static inline int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offs size_t length) {return -EINVAL ; } -static inline int ib_umem_find_best_pgsz (struct ib_umem *umem, -unsigned long pgsz_bitmap, -unsigned long virt) { -return -EINVAL ; +static inline unsigned long ib_umem_find_best_pgsz (struct ib_umem *umem, +unsigned long pgsz_bitmap, +unsigned long virt) +{ +return 0 ; }#endif /* CONFIG_INFINIBAND_USER_MEM */
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 334/633 powerpc/pseries: explicitly reschedule during drmem_lmb list traversal
In reply to Greg Kroah-HartmanFrom: Nathan Lynch <[email protected]>
[ Upstream commit 9d6792ffe140240ae54c881cc4183f9acc24b4df ]
The drmem lmb list can have hundreds of thousands of entries, and unfortunately lookups take the form of linear searches. As long as this is the case, traversals have the potential to monopolize the CPU and provoke lockup reports, workqueue stalls, and the like unless they explicitly yield.
Rather than placing cond_resched() calls within various for_each_drmem_lmb() loop blocks in the code, put it in the iteration expression of the loop macro itself so users can't omit it.
Introduce a drmem_lmb_next() iteration helper function which calls cond_resched() at a regular interval during array traversal. Each iteration of the loop in DLPAR code paths can involve around ten RTAS calls which can each take up to 250us, so this ensures the check is performed at worst every few milliseconds.
--- arch/powerpc/include/asm/drmem.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
arch/powerpc/include/asm/drmem.h +17 -1
@@ -8,6 +8,8 @@ #ifndef _ASM_POWERPC_LMB_H #define _ASM_POWERPC_LMB_H +#include <linux/sched.h> + struct drmem_lmb { u64 base_addr; u32 drc_index;
@@ -26,8 +28,22 @@ struct drmem_lmb_info {extern struct drmem_lmb_info *drmem_info; +static inline struct drmem_lmb *drmem_lmb_next (struct drmem_lmb *lmb, +const struct drmem_lmb *start) +{ +/* +* DLPAR code paths can take several milliseconds per element +* when interacting with firmware. Ensure that we don't +* unfairly monopolize the CPU. +*/ +if (((++lmb - start) %16 ) ==0 ) +cond_resched (); + +return lmb; +} +#define for_each_drmem_lmb_in_range (lmb, start, end) \ - for ((lmb) = (start); (lmb) < (end); (lmb)++) + for ((lmb) = (start); (lmb) < (end); lmb = drmem_lmb_next(lmb, start))#define for_each_drmem_lmb (lmb) \ for_each_drmem_lmb_in_range((lmb), \
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 335/633 pseries/drmem: dont cache node id in drmem_lmb struct
In reply to Greg Kroah-HartmanFrom: Scott Cheloha <[email protected]>
[ Upstream commit e5e179aa3a39c818db8fbc2dce8d2cd24adaf657 ]
At memory hot-remove time we can retrieve an LMB's nid from its corresponding memory_block. There is no need to store the nid in multiple locations.
Note that lmb_to_memblock() uses find_memory_block() to get the corresponding memory_block. As find_memory_block() runs in sub-linear time this approach is negligibly slower than what we do at present.
In exchange for this lookup at hot-remove time we no longer need to call memory_add_physaddr_to_nid() during drmem_init() for each LMB. On powerpc, memory_add_physaddr_to_nid() is a linear search, so this spares us an O(n^2) initialization during boot.
On systems with many LMBs that initialization overhead is palpable and disruptive. For example, on a box with 249854 LMBs we're seeing drmem_init() take upwards of 30 seconds to complete:
[ 53.721639] drmem: initializing drmem v2 [ 80.604346] watchdog: BUG: soft lockup - CPU#65 stuck for 23s! [swapper/0:1] [ 80.604377] Modules linked in: [ 80.604389] CPU: 65 PID: 1 Comm: swapper/0 Not tainted 5.6.0-rc2+ #4 [ 80.604397] NIP: c0000000000a4980 LR: c0000000000a4940 CTR: 0000000000000000 [ 80.604407] REGS: c0002dbff8493830 TRAP: 0901 Not tainted (5.6.0-rc2+) [ 80.604412] MSR: 8000000002009033 <SF,VEC,EE,ME,IR,DR,RI,LE> CR: 44000248 XER: 0000000d [ 80.604431] CFAR: c0000000000a4a38 IRQMASK: 0 [ 80.604431] GPR00: c0000000000a4940 c0002dbff8493ac0 c000000001904400 c0003cfffffede30 [ 80.604431] GPR04: 0000000000000000 c000000000f4095a 000000000000002f 0000000010000000 [ 80.604431] GPR08: c0000bf7ecdb7fb8 c0000bf7ecc2d3c8 0000000000000008 c00c0002fdfb2001 [ 80.604431] GPR12: 0000000000000000 c00000001e8ec200 [ 80.604477] NIP [c0000000000a4980] hot_add_scn_to_nid+0xa0/0x3e0 [ 80.604486] LR [c0000000000a4940] hot_add_scn_to_nid+0x60/0x3e0 [ 80.604492] Call Trace: [ 80.604498] [c0002dbff8493ac0] [c0000000000a4940] hot_add_scn_to_nid+0x60/0x3e0 (unreliable) [ 80.604509] [c0002dbff8493b20] [c000000000087c10] memory_add_physaddr_to_nid+0x20/0x60 [ 80.604521] [c0002dbff8493b40] [c0000000010d4880] drmem_init+0x25c/0x2f0 [ 80.604530] [c0002dbff8493c10] [c000000000010154] do_one_initcall+0x64/0x2c0 [ 80.604540] [c0002dbff8493ce0] [c0000000010c4aa0] kernel_init_freeable+0x2d8/0x3a0 [ 80.604550] [c0002dbff8493db0] [c000000000010824] kernel_init+0x2c/0x148 [ 80.604560] [c0002dbff8493e20] [c00000000000b648] ret_from_kernel_thread+0x5c/0x74 [ 80.604567] Instruction dump: [ 80.604574] 392918e8 e9490000 e90a000a e92a0000 80ea000c 1d080018 3908ffe8 7d094214 [ 80.604586] 7fa94040 419d00dc e9490010 714a0088 <2faa0008> 409e00ac e9490000 7fbe5040 [ 89.047390] drmem: 249854 LMB(s)
With a patched kernel on the same machine we're no longer seeing the soft lockup. drmem_init() now completes in negligible time, even when the LMB count is large.
--- arch/powerpc/include/asm/drmem.h | 21 ---------------- arch/powerpc/mm/drmem.c | 6 +---- .../platforms/pseries/hotplug-memory.c | 24 ++++++++++++------- 3 files changed, 17 insertions(+), 34 deletions(-)
arch/powerpc/include/asm/drmem.h +0 -21
@@ -15,9 +15,6 @@ struct drmem_lmb {u32 drc_index;u32 aa_index;u32 flags; -#ifdef CONFIG_MEMORY_HOTPLUG -int nid; -#endif };struct drmem_lmb_info {
@@ -120,22 +117,4 @@ static inline void invalidate_lmb_associativity_index(struct drmem_lmb *lmb) lmb->aa_index = 0xffffffff; } -#ifdef CONFIG_MEMORY_HOTPLUG -static inline void lmb_set_nid (struct drmem_lmb *lmb) -{ - lmb->nid =memory_add_physaddr_to_nid (lmb->base_addr); -} -static inline void lmb_clear_nid (struct drmem_lmb *lmb) -{ - lmb->nid =-1 ; -} -#else -static inline void lmb_set_nid (struct drmem_lmb *lmb) -{ -} -static inline void lmb_clear_nid (struct drmem_lmb *lmb) -{ -} -#endif -#endif /* _ASM_POWERPC_LMB_H */
arch/powerpc/mm/drmem.c +1 -5
@@ -362,10 +362,8 @@ static void __init init_drmem_v1_lmbs(const __be32 *prop)if (!drmem_info->lmbs)return ; -for_each_drmem_lmb (lmb) { +for_each_drmem_lmb (lmb)read_drconf_v1_cell (lmb, &prop); -lmb_set_nid (lmb); - } }static void __init init_drmem_v2_lmbs (const __be32 *prop)
@@ -410,8 +408,6 @@ static void __init init_drmem_v2_lmbs(const __be32 *prop) lmb->aa_index = dr_cell.aa_index; lmb->flags = dr_cell.flags; - -lmb_set_nid (lmb); } } }
arch/powerpc/platforms/pseries/hotplug-memory.c +16 -8
@@ -356,25 +356,32 @@ static int dlpar_add_lmb(struct drmem_lmb *);static int dlpar_remove_lmb (struct drmem_lmb *lmb) { +struct memory_block *mem_block;unsigned long block_sz;int rc;if (!lmb_is_removable (lmb))return -EINVAL ; + mem_block =lmb_to_memblock (lmb); +if (mem_block ==NULL ) +return -EINVAL ; + rc =dlpar_offline_lmb (lmb); -if (rc) +if (rc) { +put_device (&mem_block->dev);return rc; + } block_sz =pseries_memory_block_size (); -__remove_memory (lmb->nid, lmb->base_addr, block_sz); +__remove_memory (mem_block->nid, lmb->base_addr, block_sz); +put_device (&mem_block->dev);/* Update memory regions for memory remove */ memblock_remove (lmb->base_addr, block_sz);invalidate_lmb_associativity_index (lmb); -lmb_clear_nid (lmb); lmb->flags &= ~DRCONF_MEM_ASSIGNED ;return 0 ;
@@ -631,7 +638,7 @@ static int dlpar_memory_remove_by_ic(u32 lmbs_to_remove, u32 drc_index)static int dlpar_add_lmb (struct drmem_lmb *lmb) {unsigned long block_sz; -int rc; +int nid, rc;if (lmb->flags &DRCONF_MEM_ASSIGNED )return -EINVAL ;
@@ -642,11 +649,13 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb)return rc; } -lmb_set_nid (lmb); block_sz =memory_block_size_bytes (); +/* Find the node id for this address. */ + nid =memory_add_physaddr_to_nid (lmb->base_addr); +/* Add the memory */ - rc =__add_memory (lmb->nid, lmb->base_addr, block_sz); + rc =__add_memory (nid, lmb->base_addr, block_sz);if (rc) {invalidate_lmb_associativity_index (lmb);return rc;
@@ -654,9 +663,8 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb) rc =dlpar_online_lmb (lmb);if (rc) { -__remove_memory (lmb->nid, lmb->base_addr, block_sz); +__remove_memory (nid, lmb->base_addr, block_sz);invalidate_lmb_associativity_index (lmb); -lmb_clear_nid (lmb); }else { lmb->flags |=DRCONF_MEM_ASSIGNED ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 336/633 RDMA/mlx5: Fix potential race between destroy and CQE poll
In reply to Greg Kroah-HartmanFrom: Leon Romanovsky <[email protected]>
[ Upstream commit 4b916ed9f9e85f705213ca8d69771d3c1cd6ee5a ]
The SRQ can be destroyed right before mlx5_cmd_get_srq is called. In such case the latter will return NULL instead of expected SRQ.
--- drivers/infiniband/hw/mlx5/cq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/infiniband/hw/mlx5/cq.c +3 -2
@@ -168,7 +168,7 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, {enum rdma_link_layer ll =rdma_port_get_link_layer (qp->ibqp.device,1 );struct mlx5_ib_dev *dev =to_mdev (qp->ibqp.device); -struct mlx5_ib_srq *srq; +struct mlx5_ib_srq *srq =NULL ;struct mlx5_ib_wq *wq;u16 wqe_ctr;u8 roce_packet_type;
@@ -180,7 +180,8 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe,if (qp->ibqp.xrcd) { msrq =mlx5_cmd_get_srq (dev,be32_to_cpu (cqe->srqn)); - srq =to_mibsrq (msrq); +if (msrq) + srq =to_mibsrq (msrq); }else { srq =to_msrq (qp->ibqp.srq); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 337/633 mtd: mtdoops: Dont write panic data twice
In reply to Greg Kroah-HartmanFrom: Mark Tomlinson <[email protected]>
[ Upstream commit c1cf1d57d1492235309111ea6a900940213a9166 ]
If calling mtdoops_write, don't also schedule work to be done later.
Although this appears to not be causing an issue, possibly because the scheduled work will never get done, it is confusing.
--- drivers/mtd/mtdoops.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/mtd/mtdoops.c +6 -5
@@ -279,12 +279,13 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper,kmsg_dump_get_buffer (dumper, true, cxt->oops_buf +MTDOOPS_HEADER_SIZE , record_size -MTDOOPS_HEADER_SIZE ,NULL ); -/* Panics must be written immediately */ -if (reason !=KMSG_DUMP_OOPS ) +if (reason !=KMSG_DUMP_OOPS ) { +/* Panics must be written immediately */ mtdoops_write (cxt,1 ); - -/* For other cases, schedule work to write it "nicely" */ -schedule_work (&cxt->work_write); + }else { +/* For other cases, schedule work to write it "nicely" */ +schedule_work (&cxt->work_write); + } }static void mtdoops_notify_add (struct mtd_info *mtd)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 338/633 perf tools: Make GTK2 support opt-in
In reply to Greg Kroah-HartmanFrom: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 4751bddd3f983af2004ec470ca38b42d7a8a53bc ]
This is bitrotting, nobody is stepping up to work on it, and since we treat warnings as errors, feature detection is failing in its main, faster test (tools/build/feature/test-all.c) because of the GTK+2 infobar check.
So make this opt-in, at some point ditch this if nobody volunteers to take care of this.
--- tools/build/Makefile.feature | 5 ++--- tools/build/feature/Makefile | 2 +- tools/build/feature/test-all.c | 10 ---------- tools/perf/Makefile.config | 4 +++- tools/perf/Makefile.perf | 6 +++--- tools/perf/builtin-version.c | 1 - 6 files changed, 9 insertions(+), 19 deletions(-)
tools/build/Makefile.feature +2 -3
@@ -38,8 +38,6 @@ FEATURE_TESTS_BASIC := \ get_current_dir_name \ gettid \ glibc \ - gtk2 \ - gtk2-infobar \ libbfd \ libcap \ libelf \
@@ -81,6 +79,8 @@ FEATURE_TESTS_EXTRA := \ compile-32 \ compile-x32 \ cplus-demangle \ + gtk2 \ + gtk2-infobar \ hello \ libbabeltrace \ libbfd-liberty \
@@ -110,7 +110,6 @@ FEATURE_DISPLAY ?= \ dwarf \ dwarf_getlocations \ glibc \ - gtk2 \ libbfd \ libcap \ libelf \
tools/build/feature/Makefile +1 -1
@@ -89,7 +89,7 @@ __BUILDXX = $(CXX) $(CXXFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$( ############################### $(OUTPUT)test-all.bin: - $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma + $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -I/usr/include/slang -lslang $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma $(OUTPUT)test-hello.bin: $(BUILD)
tools/build/feature/test-all.c +0 -10
@@ -78,14 +78,6 @@# include "test-libslang.c" #undef main -#define main main_test_gtk2 -# include "test-gtk2.c" -#undef main - -#define main main_test_gtk2_infobar -# include "test-gtk2-infobar.c" -#undef main -#define main main_test_libbfd# include "test-libbfd.c" #undef main
@@ -205,8 +197,6 @@ int main(int argc, char *argv[])main_test_libelf_getshdrstrndx ();main_test_libunwind ();main_test_libslang (); -main_test_gtk2 (argc, argv); -main_test_gtk2_infobar (argc, argv);main_test_libbfd ();main_test_backtrace ();main_test_libnuma ();
tools/perf/Makefile.config +3 -1
@@ -716,12 +716,14 @@ ifndef NO_SLANG endif endif -ifndef NO_GTK2 +ifdef GTK2 FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) + $(call feature_check,gtk2) ifneq ($(feature-gtk2), 1) msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); NO_GTK2 := 1 else + $(call feature_check,gtk2-infobar) ifeq ($(feature-gtk2-infobar), 1) GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT endif
tools/perf/Makefile.perf +3 -3
@@ -48,7 +48,7 @@ include ../scripts/utilities.mak # # Define NO_SLANG if you do not want TUI support. # -# Define NO_GTK2 if you do not want GTK+ GUI support. +# Define GTK2 if you want GTK+ GUI support. # # Define NO_DEMANGLE if you do not want C++ symbol demangling. #
@@ -384,7 +384,7 @@ ifneq ($(OUTPUT),) CFLAGS += -I$(OUTPUT) endif -ifndef NO_GTK2 +ifdef GTK2 ALL_PROGRAMS += $(OUTPUT)libperf-gtk.so GTK_IN := $(OUTPUT)gtk-in.o endif
@@ -876,7 +876,7 @@ check: $(OUTPUT)common-cmds.h ### Installation rules -ifndef NO_GTK2 +ifdef GTK2 install-gtk: $(OUTPUT)libperf-gtk.so $(call QUIET_INSTALL, 'GTK UI') \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \
tools/perf/builtin-version.c +0 -1
@@ -60,7 +60,6 @@ static void library_status(void)STATUS (HAVE_DWARF_SUPPORT , dwarf);STATUS (HAVE_DWARF_GETLOCATIONS_SUPPORT , dwarf_getlocations);STATUS (HAVE_GLIBC_SUPPORT , glibc); -STATUS (HAVE_GTK2_SUPPORT , gtk2);#ifndef HAVE_SYSCALL_TABLE_SUPPORT STATUS (HAVE_LIBAUDIT_SUPPORT , libaudit);#endif
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 339/633 tools feature: Add missing -lzstd to the fast path feature detection
In reply to Greg Kroah-HartmanFrom: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 6c014694b1d2702cdc736d17b60746e7b95ba664 ]
We were failing that due to GTK2+ and then for the ZSTD test, which made test-all.c, the fast path feature detection file to fail and thus trigger building all of the feature tests, slowing down the test.
Eventually the ZSTD test would be built and would succeed, since it had the needed -lzstd, avoiding:
$ cat /tmp/build/perf/feature/test-all.make.output /usr/bin/ld: /tmp/ccRRJQ4u.o: in function `main_test_libzstd': /home/acme/git/perf/tools/build/feature/test-libzstd.c:8: undefined reference to `ZSTD_createCStream' /usr/bin/ld: /home/acme/git/perf/tools/build/feature/test-libzstd.c:9: undefined reference to `ZSTD_freeCStream' collect2: error: ld returned 1 exit status $
Fix it by adding -lzstd to the test-all target.
Now I need an entry to 'perf test' to make sure that /tmp/build/perf/feature/test-all.make.output is empty...
--- tools/build/feature/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/build/feature/Makefile +1 -1
@@ -89,7 +89,7 @@ __BUILDXX = $(CXX) $(CXXFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$( ############################### $(OUTPUT)test-all.bin: - $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -I/usr/include/slang -lslang $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma + $(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -I/usr/include/slang -lslang $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma -lzstd $(OUTPUT)test-hello.bin: $(BUILD)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 340/633 ARM: 9007/1: l2c: fix prefetch bits init in L2X0_AUX_CTRL using DT values
In reply to Greg Kroah-HartmanFrom: Guillaume Tucker <[email protected]>
[ Upstream commit 8e007b367a59bcdf484c81f6df9bd5a4cc179ca6 ]
The L310_PREFETCH_CTRL register bits 28 and 29 to enable data and instruction prefetch respectively can also be accessed via the L2X0_AUX_CTRL register. They appear to be actually wired together in hardware between the registers. Changing them in the prefetch register only will get undone when restoring the aux control register later on. For this reason, set these bits in both registers during initialisation according to the devicetree property values.
--- arch/arm/mm/cache-l2x0.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
arch/arm/mm/cache-l2x0.c +12 -4
@@ -1249,20 +1249,28 @@ static void __init l2c310_of_parse(const struct device_node *np, ret =of_property_read_u32 (np,"prefetch-data" , &val);if (ret ==0 ) { -if (val) +if (val) { prefetch |=L310_PREFETCH_CTRL_DATA_PREFETCH ; -else + *aux_val |=L310_PREFETCH_CTRL_DATA_PREFETCH ; + }else { prefetch &= ~L310_PREFETCH_CTRL_DATA_PREFETCH ; + *aux_val &= ~L310_PREFETCH_CTRL_DATA_PREFETCH ; + } + *aux_mask &= ~L310_PREFETCH_CTRL_DATA_PREFETCH ; }else if (ret != -EINVAL ) {pr_err ("L2C-310 OF prefetch-data property value is missing\n" ); } ret =of_property_read_u32 (np,"prefetch-instr" , &val);if (ret ==0 ) { -if (val) +if (val) { prefetch |=L310_PREFETCH_CTRL_INSTR_PREFETCH ; -else + *aux_val |=L310_PREFETCH_CTRL_INSTR_PREFETCH ; + }else { prefetch &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH ; + *aux_val &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH ; + } + *aux_mask &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH ; }else if (ret != -EINVAL ) {pr_err ("L2C-310 OF prefetch-instr property value is missing\n" ); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 341/633 xfs: fix finobt btree block recovery ordering
In reply to Greg Kroah-HartmanFrom: Dave Chinner <[email protected]>
[ Upstream commit 671459676ab0e1d371c8d6b184ad1faa05b6941e ]
Nathan popped up on #xfs and pointed out that we fail to handle finobt btree blocks in xlog_recover_get_buf_lsn(). This means they always fall through the entire magic number matching code to "recover immediately". Whilst most of the time this is the correct behaviour, occasionally it will be incorrect and could potentially overwrite more recent metadata because we don't check the LSN in the on disk metadata at all.
This bug has been present since the finobt was first introduced, and is a potential cause of the occasional xfs_iget_check_free_state() failures we see that indicate that the inode btree state does not match the on disk inode state.
--- fs/xfs/xfs_buf_item_recover.c | 2 ++ 1 file changed, 2 insertions(+)
fs/xfs/xfs_buf_item_recover.c +2 -0
@@ -721,6 +721,8 @@ xlog_recover_get_buf_lsn(case XFS_ABTC_MAGIC :case XFS_RMAP_CRC_MAGIC :case XFS_REFC_CRC_MAGIC : +case XFS_FIBT_CRC_MAGIC : +case XFS_FIBT_MAGIC :case XFS_IBT_CRC_MAGIC :case XFS_IBT_MAGIC : {struct xfs_btree_block *btb = blk;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 342/633 m68knommu: include SDHC support only when hardware has it
In reply to Greg Kroah-HartmanFrom: Greg Ungerer <[email protected]>
[ Upstream commit 322c512f476f07e960cecd447ef22c15bed0e5f1 ]
The mere fact that the kernel has the MMC subsystem enabled (CONFIG_MMC enabled) does not mean that the underlying hardware platform has the SDHC hardware present. Within the ColdFire hardware defines that is signified by MCFSDHC_BASE being defined with an address.
The platform data for the ColdFire parts is including the SDHC hardware if CONFIG_MMC is enabled, instead of MCFSDHC_BASE. This means that if you are compiling for a ColdFire target that does not support SDHC but enable CONFIG_MMC you will fail to compile with errors like this:
arch/m68k/coldfire/device.c:565:12: error: ‘MCFSDHC_BASE’ undeclared here (not in a function)
.start = MCFSDHC_BASE,
^
arch/m68k/coldfire/device.c:566:25: error: ‘MCFSDHC_SIZE’ undeclared here (not in a function)
.end = MCFSDHC_BASE + MCFSDHC_SIZE - 1,
^
arch/m68k/coldfire/device.c:569:12: error: ‘MCF_IRQ_SDHC’ undeclared here (not in a function)
.start = MCF_IRQ_SDHC,
^
Make the SDHC platform support depend on MCFSDHC_BASE, that is only include it if the specific ColdFire SoC has that hardware module.
--- arch/m68k/coldfire/device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/m68k/coldfire/device.c +3 -3
@@ -554,7 +554,7 @@ static struct platform_device mcf_edma = { };#endif /* IS_ENABLED(CONFIG_MCF_EDMA) */ -#if IS_ENABLED (CONFIG_MMC ) +#ifdef MCFSDHC_BASE static struct mcf_esdhc_platform_data mcf_esdhc_data = { .max_bus_width =4 , .cd_type = ESDHC_CD_NONE,
@@ -579,7 +579,7 @@ static struct platform_device mcf_esdhc = { .resource = mcf_esdhc_resources, .dev.platform_data = &mcf_esdhc_data, }; -#endif /* IS_ENABLED(CONFIG_MMC) */ +#endif /* MCFSDHC_BASE */ static struct platform_device *mcf_devices[]__initdata = { &mcf_uart,
@@ -613,7 +613,7 @@ static struct platform_device *mcf_devices[] __initdata = {#if IS_ENABLED (CONFIG_MCF_EDMA ) &mcf_edma,#endif -#if IS_ENABLED (CONFIG_MMC ) +#ifdef MCFSDHC_BASE &mcf_esdhc,#endif };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 343/633 arc: plat-hsdk: fix kconfig dependency warning when !RESET_CONTROLLER
In reply to Greg Kroah-HartmanFrom: Necip Fazil Yildiran <[email protected]>
[ Upstream commit 63bcf87cb1c57956e1179f1a78dde625c7e3cba7 ]
When ARC_SOC_HSDK is enabled and RESET_CONTROLLER is disabled, it results in the following Kbuild warning:
WARNING: unmet direct dependencies detected for RESET_HSDK
Depends on [n]: RESET_CONTROLLER [=n] && HAS_IOMEM [=y] && (ARC_SOC_HSDK [=y] || COMPILE_TEST [=n]) Selected by [y]:
- ARC_SOC_HSDK [=y] && ISA_ARCV2 [=y]
The reason is that ARC_SOC_HSDK selects RESET_HSDK without depending on or selecting RESET_CONTROLLER while RESET_HSDK is subordinate to RESET_CONTROLLER.
Honor the kconfig menu hierarchy to remove kconfig dependency warnings.
--- arch/arc/plat-hsdk/Kconfig | 1 + 1 file changed, 1 insertion(+)
arch/arc/plat-hsdk/Kconfig +1 -0
@@ -8,5 +8,6 @@ menuconfig ARC_SOC_HSDK select ARC_HAS_ACCL_REGS select ARC_IRQ_NO_AUTOSAVE select CLK_HSDK + select RESET_CONTROLLER select RESET_HSDK select HAVE_PCI
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 344/633 ida: Free allocated bitmap in error path
In reply to Greg Kroah-HartmanFrom: Matthew Wilcox (Oracle) <[email protected]>
[ Upstream commit a219b856a2b993da234108307be772448f22b0ce ]
If a bitmap needs to be allocated, and then by the time the thread is scheduled to be run again all the indices which would satisfy the allocation have been allocated then we would leak the allocation. Almost impossible to hit in practice, but a trivial fix. Found by Coverity.
--- lib/idr.c | 1 + tools/testing/radix-tree/idr-test.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+)
lib/idr.c +1 -0
@@ -470,6 +470,7 @@ int ida_alloc_range(struct ida *ida, unsigned int min, unsigned int max, goto retry; nospc:xas_unlock_irqrestore (&xas, flags); +kfree (alloc);return -ENOSPC ; }EXPORT_SYMBOL (ida_alloc_range);
tools/testing/radix-tree/idr-test.c +29 -0
@@ -523,8 +523,27 @@ static void *ida_random_fn(void *arg)return NULL ; } +static void *ida_leak_fn (void *arg) +{ +struct ida *ida = arg; +time_t s =time (NULL ); +int i, ret; + +rcu_register_thread (); + +do for (i =0 ; i <1000 ; i++) { + ret =ida_alloc_range (ida,128 ,128 ,GFP_KERNEL ); +if (ret >=0 ) +ida_free (ida,128 ); + }while (time (NULL ) < s +2 ); + +rcu_unregister_thread (); +return NULL ; +} +void ida_thread_tests (void ) { +DEFINE_IDA (ida);pthread_t threads[20 ];int i;
@@ -536,6 +555,16 @@ void ida_thread_tests(void)while (i--)pthread_join (threads[i],NULL ); + +for (i =0 ; i <ARRAY_SIZE (threads); i++) +if (pthread_create (&threads[i],NULL , ida_leak_fn, &ida)) { +perror ("creating ida thread" ); +exit (1 ); + } + +while (i--) +pthread_join (threads[i],NULL ); +assert (ida_is_empty (&ida)); }void ida_tests (void )
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 345/633 xfs: limit entries returned when counting fsmap records
In reply to Greg Kroah-HartmanFrom: Darrick J. Wong <[email protected]>
[ Upstream commit acd1ac3aa22fd58803a12d26b1ab7f70232f8d8d ]
If userspace asked fsmap to count the number of entries, we cannot return more than UINT_MAX entries because fmh_entries is u32. Therefore, stop counting if we hit this limit or else we will waste time to return truncated results.
--- fs/xfs/xfs_fsmap.c | 3 +++ 1 file changed, 3 insertions(+)
fs/xfs/xfs_fsmap.c +3 -0
@@ -256,6 +256,9 @@ xfs_getfsmap_helper(/* Are we just counting mappings? */ if (info->head->fmh_count ==0 ) { +if (info->head->fmh_entries ==UINT_MAX ) +return -ECANCELED ; +if (rec_daddr > info->next_daddr) info->head->fmh_entries++;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 346/633 xfs: fix deadlock and streamline xfs_getfsmap performance
In reply to Greg Kroah-HartmanFrom: Darrick J. Wong <[email protected]>
[ Upstream commit 8ffa90e1145c70c7ac47f14b59583b2296d89e72 ]
Refactor xfs_getfsmap to improve its performance: instead of indirectly calling a function that copies one record to userspace at a time, create a shadow buffer in the kernel and copy the whole array once at the end. On the author's computer, this reduces the runtime on his /home by ~20%.
This also eliminates a deadlock when running GETFSMAP against the realtime device. The current code locks the rtbitmap to create fsmappings and copies them into userspace, having not released the rtbitmap lock. If the userspace buffer is an mmap of a sparse file that itself resides on the realtime device, the write page fault will recurse into the fs for allocation, which will deadlock on the rtbitmap lock.
--- fs/xfs/xfs_fsmap.c | 45 +++++++------- fs/xfs/xfs_fsmap.h | 6 +- fs/xfs/xfs_ioctl.c | 144 ++++++++++++++++++++++++++++++--------------- 3 files changed, 124 insertions(+), 71 deletions(-)
fs/xfs/xfs_fsmap.c +25 -20
@@ -26,7 +26,7 @@#include "xfs_rtalloc.h" /* Convert an xfs_fsmap to an fsmap. */ -void +static void xfs_fsmap_from_internal (struct fsmap *dest,struct xfs_fsmap *src)
@@ -155,8 +155,7 @@ xfs_fsmap_owner_from_rmap(/* getfsmap query state */ struct xfs_getfsmap_info {struct xfs_fsmap_head *head; -xfs_fsmap_format_t formatter;/* formatting fn */ -void *format_arg;/* format buffer */ +struct fsmap *fsmap_recs;/* mapping records */ struct xfs_buf *agf_bp;/* AGF, for refcount queries */ xfs_daddr_t next_daddr;/* next daddr we expect */ u64 missing_owner;/* owner of holes */
@@ -224,6 +223,20 @@ xfs_getfsmap_is_shared(return 0 ; } +static inline void +xfs_getfsmap_format ( +struct xfs_mount *mp, +struct xfs_fsmap *xfm, +struct xfs_getfsmap_info *info) +{ +struct fsmap *rec; + +trace_xfs_getfsmap_mapping (mp, xfm); + + rec = &info->fsmap_recs[info->head->fmh_entries++]; +xfs_fsmap_from_internal (rec, xfm); +} +/* * Format a reverse mapping for getfsmap, having translated rm_startblock * into the appropriate daddr units.
@@ -288,10 +301,7 @@ xfs_getfsmap_helper( fmr.fmr_offset =0 ; fmr.fmr_length = rec_daddr - info->next_daddr; fmr.fmr_flags =FMR_OF_SPECIAL_OWNER ; - error = info->formatter (&fmr, info->format_arg); -if (error) -return error; - info->head->fmh_entries++; +xfs_getfsmap_format (mp, &fmr, info); }if (info->last)
@@ -323,11 +333,8 @@ xfs_getfsmap_helper(if (shared) fmr.fmr_flags |=FMR_OF_SHARED ; } - error = info->formatter (&fmr, info->format_arg); -if (error) -return error; - info->head->fmh_entries++; +xfs_getfsmap_format (mp, &fmr, info); out: rec_daddr +=XFS_FSB_TO_BB (mp, rec->rm_blockcount);if (info->next_daddr < rec_daddr)
@@ -795,11 +802,11 @@ xfs_getfsmap_check_keys(#endif /* CONFIG_XFS_RT */ /* -* Get filesystem's extents as described in head, and format for -* output. Calls formatter to fill the user's buffer until all -* extents are mapped, until the passed-in head->fmh_count slots have -* been filled, or until the formatter short-circuits the loop, if it -* is tracking filled-in extents on its own. +* Get filesystem's extents as described in head, and format for output. Fills +* in the supplied records array until there are no more reverse mappings to +* return or head.fmh_entries == head.fmh_count. In the second case, this +* function returns -ECANCELED to indicate that more records would have been +* returned. * * Key to Confusion * ----------------
@@ -819,8 +826,7 @@ intxfs_getfsmap ( struct xfs_mount *mp, struct xfs_fsmap_head *head, - xfs_fsmap_format_t formatter, - void *arg) + struct fsmap *fsmap_recs) { struct xfs_trans *tp = NULL;struct xfs_fsmap dkeys[2 ];/* per-dev keys */
@@ -895,8 +901,7 @@ xfs_getfsmap( info.next_daddr = head->fmh_keys[0 ].fmr_physical + head->fmh_keys[0 ].fmr_length; - info.formatter = formatter; - info.format_arg = arg; + info.fsmap_recs = fsmap_recs; info.head = head;/*
fs/xfs/xfs_fsmap.h +1 -5
@@ -27,13 +27,9 @@ struct xfs_fsmap_head { struct xfs_fsmap fmh_keys[2]; /* low and high keys */ }; -void xfs_fsmap_from_internal (struct fsmap *dest,struct xfs_fsmap *src);void xfs_fsmap_to_internal (struct xfs_fsmap *dest,struct fsmap *src); -/* fsmap to userspace formatter - copy to user & advance pointer */ -typedef int (*xfs_fsmap_format_t )(struct xfs_fsmap *,void *); -int xfs_getfsmap (struct xfs_mount *mp,struct xfs_fsmap_head *head, -xfs_fsmap_format_t formatter,void *arg); +struct fsmap *out_recs);#endif /* __XFS_FSMAP_H__ */
fs/xfs/xfs_ioctl.c +98 -46
175 lines not on this page · raw message
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 347/633 nfs: add missing "posix" local_lock constant table definition
In reply to Greg Kroah-HartmanFrom: Scott Mayhew <[email protected]>
[ Upstream commit a2d24bcb97dc7b0be1cb891e60ae133bdf36c786 ]
"mount -o local_lock=posix..." was broken by the mount API conversion due to the missing constant.
--- fs/nfs/fs_context.c | 1 + 1 file changed, 1 insertion(+)
fs/nfs/fs_context.c +1 -0
@@ -94,6 +94,7 @@ enum {static const struct constant_table nfs_param_enums_local_lock[] = { {"all" , Opt_local_lock_all }, {"flock" , Opt_local_lock_flock }, + {"posix" , Opt_local_lock_posix }, {"none" , Opt_local_lock_none }, {} };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 348/633 xfs: fix high key handling in the rt allocators query_range function
In reply to Greg Kroah-HartmanFrom: Darrick J. Wong <[email protected]>
[ Upstream commit d88850bd5516a77c6f727e8b6cefb64e0cc929c7 ]
Fix some off-by-one errors in xfs_rtalloc_query_range. The highest key in the realtime bitmap is always one less than the number of rt extents, which means that the key clamp at the start of the function is wrong. The 4th argument to xfs_rtfind_forw is the highest rt extent that we want to probe, which means that passing 1 less than the high key is wrong. Finally, drop the rem variable that controls the loop because we can compare the iteration point (rtstart) against the high key directly.
The sordid history of this function is that the original commit (fb3c3) incorrectly passed (high_rec->ar_startblock - 1) as the 'limit' parameter to xfs_rtfind_forw. This was wrong because the "high key" is supposed to be the largest key for which the caller wants result rows, not the key for the first row that could possibly be outside the range that the caller wants to see.
A subsequent attempt (8ad56) to strengthen the parameter checking added incorrect clamping of the parameters to the number of rt blocks in the system (despite the bitmap functions all taking units of rt extents) to avoid querying ranges past the end of rt bitmap file but failed to fix the incorrect _rtfind_forw parameter. The original _rtfind_forw parameter error then survived the conversion of the startblock and blockcount fields to rt extents (a0e5c), and the most recent off-by-one fix (a3a37) thought it was patching a problem when the end of the rt volume is not in use, but none of these fixes actually solved the original problem that the author was confused about the "limit" argument to xfs_rtfind_forw.
Sadly, all four of these patches were written by this author and even his own usage of this function and rt testing were inadequate to get this fixed quickly.
Original-problem: fb3c3de2f65c ("xfs: add a couple of queries to iterate free extents in the rtbitmap")
--- fs/xfs/libxfs/xfs_rtbitmap.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
fs/xfs/libxfs/xfs_rtbitmap.c +4 -7
@@ -1018,7 +1018,6 @@ xfs_rtalloc_query_range(struct xfs_mount *mp = tp->t_mountp;xfs_rtblock_t rtstart;xfs_rtblock_t rtend; -xfs_rtblock_t rem;int is_free;int error =0 ;
@@ -1027,13 +1026,12 @@ xfs_rtalloc_query_range(if (low_rec->ar_startext >= mp->m_sb.sb_rextents || low_rec->ar_startext == high_rec->ar_startext)return 0 ; -if (high_rec->ar_startext > mp->m_sb.sb_rextents) - high_rec->ar_startext = mp->m_sb.sb_rextents; + high_rec->ar_startext =min (high_rec->ar_startext, + mp->m_sb.sb_rextents -1 );/* Iterate the bitmap, looking for discrepancies. */ rtstart = low_rec->ar_startext; - rem = high_rec->ar_startext - rtstart; -while (rem) { +while (rtstart <= high_rec->ar_startext) {/* Is the first block free? */ error =xfs_rtcheck_range (mp, tp, rtstart,1 ,1 , &rtend, &is_free);
@@ -1042,7 +1040,7 @@ xfs_rtalloc_query_range(/* How long does the extent go for? */ error =xfs_rtfind_forw (mp, tp, rtstart, - high_rec->ar_startext -1 , &rtend); + high_rec->ar_startext, &rtend);if (error)break ;
@@ -1055,7 +1053,6 @@ xfs_rtalloc_query_range(break ; } - rem -= rtend - rtstart +1 ; rtstart = rtend +1 ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 349/633 RDMA/rtrs-srv: Incorporate ib_register_client into rtrs server init
In reply to Greg Kroah-HartmanFrom: Md Haris Iqbal <[email protected]>
[ Upstream commit 558d52b2976b1db3098139aa83ceb9af9066a0e7 ]
The rnbd_server module's communication manager (cm) initialization depends on the registration of the "network namespace subsystem" of the RDMA CM agent module. As such, when the kernel is configured to load the rnbd_server and the RDMA cma module during initialization; and if the rnbd_server module is initialized before RDMA cma module, a null ptr dereference occurs during the RDMA bind operation.
Call trace: Call Trace: ? xas_load+0xd/0x80 xa_load+0x47/0x80 cma_ps_find+0x44/0x70 rdma_bind_addr+0x782/0x8b0 ? get_random_bytes+0x35/0x40 rtrs_srv_cm_init+0x50/0x80 rtrs_srv_open+0x102/0x180 ? rnbd_client_init+0x6e/0x6e rnbd_srv_init_module+0x34/0x84 ? rnbd_client_init+0x6e/0x6e do_one_initcall+0x4a/0x200 kernel_init_freeable+0x1f1/0x26e ? rest_init+0xb0/0xb0 kernel_init+0xe/0x100 ret_from_fork+0x22/0x30 Modules linked in: CR2: 0000000000000015
All this happens cause the cm init is in the call chain of the module init, which is not a preferred practice.
So remove the call to rdma_create_id() from the module init call chain. Instead register rtrs-srv as an ib client, which makes sure that the rdma_create_id() is called only when an ib device is added.
--- drivers/infiniband/ulp/rtrs/rtrs-srv.c | 76 +++++++++++++++++++++++++- drivers/infiniband/ulp/rtrs/rtrs-srv.h | 7 +++ 2 files changed, 80 insertions(+), 3 deletions(-)
drivers/infiniband/ulp/rtrs/rtrs-srv.c +73 -3
@@ -16,6 +16,7 @@#include "rtrs-srv.h" #include "rtrs-log.h" #include <rdma/ib_cm.h> +#include <rdma/ib_verbs.h> MODULE_DESCRIPTION ("RDMA Transport Server" );MODULE_LICENSE ("GPL" );
@@ -31,6 +32,7 @@ MODULE_LICENSE("GPL");static struct rtrs_rdma_dev_pd dev_pd;static mempool_t *chunk_pool;struct class *rtrs_dev_class; +static struct rtrs_srv_ib_ctx ib_ctx;static int __read_mostly max_chunk_size =DEFAULT_MAX_CHUNK_SIZE ;static int __read_mostly sess_queue_depth =DEFAULT_SESS_QUEUE_DEPTH ;
@@ -2042,6 +2044,70 @@ static void free_srv_ctx(struct rtrs_srv_ctx *ctx)kfree (ctx); } +static int rtrs_srv_add_one (struct ib_device *device) +{ +struct rtrs_srv_ctx *ctx; +int ret =0 ; + +mutex_lock (&ib_ctx.ib_dev_mutex); +if (ib_ctx.ib_dev_count) + goto out; + +/* +* Since our CM IDs are NOT bound to any ib device we will create them +* only once +*/ + ctx = ib_ctx.srv_ctx; + ret =rtrs_srv_rdma_init (ctx, ib_ctx.port); +if (ret) { +/* +* We errored out here. +* According to the ib code, if we encounter an error here then the +* error code is ignored, and no more calls to our ops are made. +*/ +pr_err ("Failed to initialize RDMA connection" ); + goto err_out; + } + +out: +/* +* Keep a track on the number of ib devices added +*/ + ib_ctx.ib_dev_count++; + +err_out: +mutex_unlock (&ib_ctx.ib_dev_mutex); +return ret; +} + +static void rtrs_srv_remove_one (struct ib_device *device,void *client_data) +{ +struct rtrs_srv_ctx *ctx; + +mutex_lock (&ib_ctx.ib_dev_mutex); + ib_ctx.ib_dev_count--; + +if (ib_ctx.ib_dev_count) + goto out; + +/* +* Since our CM IDs are NOT bound to any ib device we will remove them +* only once, when the last device is removed +*/ + ctx = ib_ctx.srv_ctx; +rdma_destroy_id (ctx->cm_id_ip); +rdma_destroy_id (ctx->cm_id_ib); + +out: +mutex_unlock (&ib_ctx.ib_dev_mutex); +} + +static struct ib_client rtrs_srv_client = { + .name ="rtrs_server" , + .add = rtrs_srv_add_one, + .remove = rtrs_srv_remove_one +}; +/** * rtrs_srv_open() - open RTRS server context * @ops: callback functions
@@ -2060,7 +2126,11 @@ struct rtrs_srv_ctx *rtrs_srv_open(struct rtrs_srv_ops *ops, u16 port)if (!ctx)return ERR_PTR (-ENOMEM ); - err =rtrs_srv_rdma_init (ctx, port); +mutex_init (&ib_ctx.ib_dev_mutex); + ib_ctx.srv_ctx = ctx; + ib_ctx.port = port; + + err =ib_register_client (&rtrs_srv_client);if (err) {free_srv_ctx (ctx);return ERR_PTR (err);
@@ -2099,8 +2169,8 @@ static void close_ctx(struct rtrs_srv_ctx *ctx)*/ void rtrs_srv_close (struct rtrs_srv_ctx *ctx) { -rdma_destroy_id (ctx->cm_id_ip); -rdma_destroy_id (ctx->cm_id_ib); +ib_unregister_client (&rtrs_srv_client); +mutex_destroy (&ib_ctx.ib_dev_mutex);close_ctx (ctx);free_srv_ctx (ctx); }
drivers/infiniband/ulp/rtrs/rtrs-srv.h +7 -0
@@ -118,6 +118,13 @@ struct rtrs_srv_ctx {struct list_head srv_list; }; +struct rtrs_srv_ib_ctx { +struct rtrs_srv_ctx *srv_ctx; +u16 port; +struct mutex ib_dev_mutex; +int ib_dev_count; +}; +extern struct class *rtrs_dev_class;void close_sess (struct rtrs_srv_sess *sess);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 350/633 RDMA/core: Delete function indirection for alloc/free kernel CQ
In reply to Greg Kroah-HartmanFrom: Leon Romanovsky <[email protected]>
[ Upstream commit 7e3c66c9a989d5b53387ceebc88b9e4a9b1d6434 ]
The ib_alloc_cq*() and ib_free_cq*() are solely kernel verbs to manage CQs and doesn't need extra indirection just to call same functions with constant parameter NULL as udata.
--- drivers/infiniband/core/cq.c | 27 +++++++--------- include/rdma/ib_verbs.h | 62 ++++-------------------------------- 2 files changed, 18 insertions(+), 71 deletions(-)
drivers/infiniband/core/cq.c +12 -15
@@ -197,24 +197,22 @@ static void ib_cq_completion_workqueue(struct ib_cq *cq, void *private) }/** -* __ib_alloc_cq_user - allocate a completion queue +* __ib_alloc_cq allocate a completion queue * @dev: device to allocate the CQ for * @private: driver private data, accessible from cq->cq_context * @nr_cqe: number of CQEs to allocate * @comp_vector: HCA completion vectors for this CQ * @poll_ctx: context to poll the CQ from. * @caller: module owner name. -* @udata: Valid user data or NULL for kernel object * * This is the proper interface to allocate a CQ for in-kernel users. A * CQ allocated with this interface will automatically be polled from the * specified context. The ULP must use wr->wr_cqe instead of wr->wr_id * to use this CQ abstraction. */ -struct ib_cq *__ib_alloc_cq_user (struct ib_device *dev,void *private, -int nr_cqe,int comp_vector, -enum ib_poll_context poll_ctx, -const char *caller,struct ib_udata *udata) +struct ib_cq *__ib_alloc_cq (struct ib_device *dev,void *private,int nr_cqe, +int comp_vector,enum ib_poll_context poll_ctx, +const char *caller) {struct ib_cq_init_attr cq_attr = { .cqe = nr_cqe,
@@ -277,7 +275,7 @@ struct ib_cq *__ib_alloc_cq_user(struct ib_device *dev, void *private, out_destroy_cq:rdma_dim_destroy (cq);rdma_restrack_del (&cq->res); - cq->device->ops.destroy_cq (cq, udata); + cq->device->ops.destroy_cq (cq,NULL ); out_free_wc:kfree (cq->wc); out_free_cq:
@@ -285,7 +283,7 @@ struct ib_cq *__ib_alloc_cq_user(struct ib_device *dev, void *private,trace_cq_alloc_error (nr_cqe, comp_vector, poll_ctx, ret);return ERR_PTR (ret); } -EXPORT_SYMBOL (__ib_alloc_cq_user); +EXPORT_SYMBOL (__ib_alloc_cq);/** * __ib_alloc_cq_any - allocate a completion queue
@@ -310,17 +308,16 @@ struct ib_cq *__ib_alloc_cq_any(struct ib_device *dev, void *private,atomic_inc_return (&counter) %min_t (int, dev->num_comp_vectors,num_online_cpus ()); -return __ib_alloc_cq_user (dev, private, nr_cqe, comp_vector, poll_ctx, - caller,NULL ); +return __ib_alloc_cq (dev, private, nr_cqe, comp_vector, poll_ctx, + caller); }EXPORT_SYMBOL (__ib_alloc_cq_any);/** -* ib_free_cq_user - free a completion queue +* ib_free_cq - free a completion queue * @cq: completion queue to free. -* @udata: User data or NULL for kernel object */ -void ib_free_cq_user (struct ib_cq *cq,struct ib_udata *udata) +void ib_free_cq (struct ib_cq *cq) {if (WARN_ON_ONCE (atomic_read (&cq->usecnt)))return ;
@@ -344,11 +341,11 @@ void ib_free_cq_user(struct ib_cq *cq, struct ib_udata *udata)rdma_dim_destroy (cq);trace_cq_free (cq);rdma_restrack_del (&cq->res); - cq->device->ops.destroy_cq (cq, udata); + cq->device->ops.destroy_cq (cq,NULL );kfree (cq->wc);kfree (cq); } -EXPORT_SYMBOL (ib_free_cq_user); +EXPORT_SYMBOL (ib_free_cq);void ib_cq_pool_init (struct ib_device *dev) {
include/rdma/ib_verbs.h +6 -56
78 lines not on this page · raw message
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 351/633 RDMA: Allow fail of destroy CQ
In reply to Greg Kroah-HartmanFrom: Leon Romanovsky <[email protected]>
[ Upstream commit 43d781b9fa562f0c6e50f62c870fbfeb9dc85213 ]
Like any other verbs objects, CQ shouldn't fail during destroy, but mlx5_ib didn't follow this contract with mixed IB verbs objects with DEVX. Such mix causes to the situation where FW and kernel are fully interdependent on the reference counting of each side.
Kernel verbs and drivers that don't have DEVX flows shouldn't fail.
--- drivers/infiniband/core/cq.c | 5 ++++- drivers/infiniband/core/verbs.c | 9 +++++++-- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 3 ++- drivers/infiniband/hw/bnxt_re/ib_verbs.h | 2 +- drivers/infiniband/hw/cxgb4/cq.c | 3 ++- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 2 +- drivers/infiniband/hw/efa/efa.h | 2 +- drivers/infiniband/hw/efa/efa_verbs.c | 3 ++- drivers/infiniband/hw/hns/hns_roce_cq.c | 3 ++- drivers/infiniband/hw/hns/hns_roce_device.h | 4 ++-- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 3 ++- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 3 ++- drivers/infiniband/hw/mlx4/cq.c | 3 ++- drivers/infiniband/hw/mlx4/mlx4_ib.h | 2 +- drivers/infiniband/hw/mlx5/cq.c | 9 +++++++-- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- drivers/infiniband/hw/mthca/mthca_provider.c | 3 ++- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 3 ++- drivers/infiniband/hw/ocrdma/ocrdma_verbs.h | 2 +- drivers/infiniband/hw/qedr/verbs.c | 5 +++-- drivers/infiniband/hw/qedr/verbs.h | 2 +- drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 4 ++-- drivers/infiniband/hw/usnic/usnic_ib_verbs.h | 2 +- drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c | 3 ++- drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h | 2 +- drivers/infiniband/sw/rdmavt/cq.c | 3 ++- drivers/infiniband/sw/rdmavt/cq.h | 2 +- drivers/infiniband/sw/rxe/rxe_verbs.c | 3 ++- drivers/infiniband/sw/siw/siw_verbs.c | 3 ++- drivers/infiniband/sw/siw/siw_verbs.h | 2 +- include/rdma/ib_verbs.h | 6 ++++-- 31 files changed, 66 insertions(+), 37 deletions(-)
drivers/infiniband/core/cq.c +4 -1
@@ -319,6 +319,8 @@ EXPORT_SYMBOL(__ib_alloc_cq_any);*/ void ib_free_cq (struct ib_cq *cq) { +int ret; +if (WARN_ON_ONCE (atomic_read (&cq->usecnt)))return ;if (WARN_ON_ONCE (cq->cqe_used))
@@ -340,8 +342,9 @@ void ib_free_cq(struct ib_cq *cq)rdma_dim_destroy (cq);trace_cq_free (cq); + ret = cq->device->ops.destroy_cq (cq,NULL ); +WARN_ONCE (ret,"Destroy of kernel CQ shouldn't fail" );rdma_restrack_del (&cq->res); - cq->device->ops.destroy_cq (cq,NULL );kfree (cq->wc);kfree (cq); }
drivers/infiniband/core/verbs.c +7 -2
@@ -2016,16 +2016,21 @@ EXPORT_SYMBOL(rdma_set_cq_moderation);int ib_destroy_cq_user (struct ib_cq *cq,struct ib_udata *udata) { +int ret; +if (WARN_ON_ONCE (cq->shared))return -EOPNOTSUPP ;if (atomic_read (&cq->usecnt))return -EBUSY ; + ret = cq->device->ops.destroy_cq (cq, udata); +if (ret) +return ret; +rdma_restrack_del (&cq->res); - cq->device->ops.destroy_cq (cq, udata);kfree (cq); -return 0 ; +return ret; }EXPORT_SYMBOL (ib_destroy_cq_user);
drivers/infiniband/hw/bnxt_re/ib_verbs.c +2 -1
@@ -2714,7 +2714,7 @@ int bnxt_re_post_recv(struct ib_qp *ib_qp, const struct ib_recv_wr *wr, }/* Completion Queues */ -void bnxt_re_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) +int bnxt_re_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) {struct bnxt_re_cq *cq;struct bnxt_qplib_nq *nq;
@@ -2730,6 +2730,7 @@ void bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)atomic_dec (&rdev->cq_count); nq->budget--;kfree (cq->cql); +return 0 ; } int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
drivers/infiniband/hw/bnxt_re/ib_verbs.h +1 -1
@@ -193,7 +193,7 @@ int bnxt_re_post_recv(struct ib_qp *qp, const struct ib_recv_wr *recv_wr, const struct ib_recv_wr **bad_recv_wr);int bnxt_re_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata); -void bnxt_re_destroy_cq (struct ib_cq *cq,struct ib_udata *udata); +int bnxt_re_destroy_cq (struct ib_cq *cq,struct ib_udata *udata);int bnxt_re_poll_cq (struct ib_cq *cq,int num_entries,struct ib_wc *wc);int bnxt_re_req_notify_cq (struct ib_cq *cq,enum ib_cq_notify_flags flags);struct ib_mr *bnxt_re_get_dma_mr (struct ib_pd *pd,int mr_access_flags);
drivers/infiniband/hw/cxgb4/cq.c +2 -1
@@ -967,7 +967,7 @@ int c4iw_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)return !err || err == -ENODATA ? npolled : err; } -void c4iw_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) +int c4iw_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) {struct c4iw_cq *chp;struct c4iw_ucontext *ucontext;
@@ -985,6 +985,7 @@ void c4iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) ucontext ? &ucontext->uctx : &chp->cq.rdev->uctx, chp->destroy_skb, chp->wr_waitp);c4iw_put_wr_wait (chp->wr_waitp); +return 0 ; } int c4iw_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
drivers/infiniband/hw/cxgb4/iw_cxgb4.h +1 -1
@@ -992,7 +992,7 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, struct ib_udata *udata);struct ib_mr *c4iw_get_dma_mr (struct ib_pd *pd,int acc);int c4iw_dereg_mr (struct ib_mr *ib_mr,struct ib_udata *udata); -void c4iw_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata); +int c4iw_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata);int c4iw_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata);int c4iw_arm_cq (struct ib_cq *ibcq,enum ib_cq_notify_flags flags);
drivers/infiniband/hw/efa/efa.h +1 -1
@@ -139,7 +139,7 @@ int efa_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata);struct ib_qp *efa_create_qp (struct ib_pd *ibpd,struct ib_qp_init_attr *init_attr,struct ib_udata *udata); -void efa_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata); +int efa_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata);int efa_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata); struct ib_mr *efa_reg_mr(struct ib_pd *ibpd, u64 start, u64 length,
drivers/infiniband/hw/efa/efa_verbs.c +2 -1
@@ -843,7 +843,7 @@ static int efa_destroy_cq_idx(struct efa_dev *dev, int cq_idx)return efa_com_destroy_cq (&dev->edev, ¶ms); } -void efa_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) +int efa_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) {struct efa_dev *dev =to_edev (ibcq->device);struct efa_cq *cq =to_ecq (ibcq);
@@ -856,6 +856,7 @@ void efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)efa_destroy_cq_idx (dev, cq->cq_idx);efa_free_mapped (dev, cq->cpu_addr, cq->dma_addr, cq->size,DMA_FROM_DEVICE ); +return 0 ; } static int cq_mmap_entries_setup(struct efa_dev *dev, struct efa_cq *cq,
drivers/infiniband/hw/hns/hns_roce_cq.c +2 -1
@@ -311,7 +311,7 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,return ret; } -void hns_roce_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) +int hns_roce_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) {struct hns_roce_dev *hr_dev =to_hr_dev (ib_cq->device);struct hns_roce_cq *hr_cq =to_hr_cq (ib_cq);
@@ -322,6 +322,7 @@ void hns_roce_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)free_cq_buf (hr_dev, hr_cq);free_cq_db (hr_dev, hr_cq, udata);free_cqc (hr_dev, hr_cq); +return 0 ; }void hns_roce_cq_completion (struct hns_roce_dev *hr_dev,u32 cqn)
drivers/infiniband/hw/hns/hns_roce_device.h +2 -2
@@ -929,7 +929,7 @@ struct hns_roce_hw {int (*poll_cq)(struct ib_cq *ibcq,int num_entries,struct ib_wc *wc);int (*dereg_mr)(struct hns_roce_dev *hr_dev,struct hns_roce_mr *mr,struct ib_udata *udata); -void (*destroy_cq)(struct ib_cq *ibcq,struct ib_udata *udata); +int (*destroy_cq)(struct ib_cq *ibcq,struct ib_udata *udata);int (*modify_cq)(struct ib_cq *cq,u16 cq_count,u16 cq_period);int (*init_eq)(struct hns_roce_dev *hr_dev);void (*cleanup_eq)(struct hns_roce_dev *hr_dev);
@@ -1246,7 +1246,7 @@ int to_hr_qp_type(int qp_type);int hns_roce_create_cq (struct ib_cq *ib_cq,const struct ib_cq_init_attr *attr,struct ib_udata *udata); -void hns_roce_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata); +int hns_roce_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata);int hns_roce_db_map_user (struct hns_roce_ucontext *context,struct ib_udata *udata,unsigned long virt,struct hns_roce_db *db);
drivers/infiniband/hw/hns/hns_roce_hw_v1.c +2 -1
@@ -3573,7 +3573,7 @@ int hns_roce_v1_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)return 0 ; } -static void hns_roce_v1_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) +static int hns_roce_v1_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) {struct hns_roce_dev *hr_dev =to_hr_dev (ibcq->device);struct hns_roce_cq *hr_cq =to_hr_cq (ibcq);
@@ -3604,6 +3604,7 @@ static void hns_roce_v1_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata) } wait_time++; } +return 0 ; }static void set_eq_cons_index_v1 (struct hns_roce_eq *eq,int req_not)
drivers/infiniband/hw/i40iw/i40iw_verbs.c +2 -1
@@ -1053,7 +1053,7 @@ void i40iw_cq_wq_destroy(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq)* @ib_cq: cq pointer * @udata: user data or NULL for kernel object */ -static void i40iw_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) +static int i40iw_destroy_cq (struct ib_cq *ib_cq,struct ib_udata *udata) {struct i40iw_cq *iwcq;struct i40iw_device *iwdev;
@@ -1065,6 +1065,7 @@ static void i40iw_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)i40iw_cq_wq_destroy (iwdev, cq);cq_free_resources (iwdev, iwcq);i40iw_rem_devusecount (iwdev); +return 0 ; }/**
drivers/infiniband/hw/mlx4/cq.c +2 -1
@@ -475,7 +475,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)return err; } -void mlx4_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) +int mlx4_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) {struct mlx4_ib_dev *dev =to_mdev (cq->device);struct mlx4_ib_cq *mcq =to_mcq (cq);
@@ -495,6 +495,7 @@ void mlx4_ib_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)mlx4_db_free (dev->dev, &mcq->db); }ib_umem_release (mcq->umem); +return 0 ; }static void dump_cqe (void *cqe)
drivers/infiniband/hw/mlx4/mlx4_ib.h +1 -1
@@ -738,7 +738,7 @@ int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period);int mlx4_ib_resize_cq (struct ib_cq *ibcq,int entries,struct ib_udata *udata);int mlx4_ib_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata); -void mlx4_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata); +int mlx4_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata);int mlx4_ib_poll_cq (struct ib_cq *ibcq,int num_entries,struct ib_wc *wc);int mlx4_ib_arm_cq (struct ib_cq *cq,enum ib_cq_notify_flags flags);void __mlx4_ib_cq_clean (struct mlx4_ib_cq *cq,u32 qpn,struct mlx4_ib_srq *srq);
drivers/infiniband/hw/mlx5/cq.c +7 -2
@@ -1024,16 +1024,21 @@ int mlx5_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,return err; } -void mlx5_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) +int mlx5_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) {struct mlx5_ib_dev *dev =to_mdev (cq->device);struct mlx5_ib_cq *mcq =to_mcq (cq); +int ret; + + ret =mlx5_core_destroy_cq (dev->mdev, &mcq->mcq); +if (ret) +return ret; -mlx5_core_destroy_cq (dev->mdev, &mcq->mcq);if (udata)destroy_cq_user (mcq, udata);else destroy_cq_kernel (dev, mcq); +return 0 ; }static int is_equal_rsn (struct mlx5_cqe64 *cqe64,u32 rsn)
drivers/infiniband/hw/mlx5/mlx5_ib.h +1 -1
@@ -1180,7 +1180,7 @@ int mlx5_ib_read_wqe_srq(struct mlx5_ib_srq *srq, int wqe_index, void *buffer, size_t buflen, size_t *bc);int mlx5_ib_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata); -void mlx5_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata); +int mlx5_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata);int mlx5_ib_poll_cq (struct ib_cq *ibcq,int num_entries,struct ib_wc *wc);int mlx5_ib_arm_cq (struct ib_cq *ibcq,enum ib_cq_notify_flags flags);int mlx5_ib_modify_cq (struct ib_cq *cq,u16 cq_count,u16 cq_period);
drivers/infiniband/hw/mthca/mthca_provider.c +2 -1
@@ -789,7 +789,7 @@ static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udareturn ret; } -static void mthca_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) +static int mthca_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) {if (udata) { struct mthca_ucontext *context =
@@ -808,6 +808,7 @@ static void mthca_destroy_cq(struct ib_cq *cq, struct ib_udata *udata) to_mcq(cq)->set_ci_db_index); }mthca_free_cq (to_mdev (cq->device),to_mcq (cq)); +return 0 ; }static inline u32 convert_access (int acc)
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +2 -1
@@ -1056,7 +1056,7 @@ static void ocrdma_flush_cq(struct ocrdma_cq *cq)spin_unlock_irqrestore (&cq->cq_lock, flags); } -void ocrdma_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) +int ocrdma_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) {struct ocrdma_cq *cq =get_ocrdma_cq (ibcq);struct ocrdma_eq *eq =NULL ;
@@ -1081,6 +1081,7 @@ void ocrdma_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)ocrdma_get_db_addr (dev, pdid), dev->nic_info.db_page_size); } +return 0 ; }static int ocrdma_add_qpn_map (struct ocrdma_dev *dev,struct ocrdma_qp *qp)
drivers/infiniband/hw/ocrdma/ocrdma_verbs.h +1 -1
@@ -72,7 +72,7 @@ void ocrdma_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata);int ocrdma_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata);int ocrdma_resize_cq (struct ib_cq *,int cqe,struct ib_udata *); -void ocrdma_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata); +int ocrdma_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata); struct ib_qp *ocrdma_create_qp(struct ib_pd *, struct ib_qp_init_attr *attrs,
drivers/infiniband/hw/qedr/verbs.c +3 -2
@@ -1050,7 +1050,7 @@ int qedr_resize_cq(struct ib_cq *ibcq, int new_cnt, struct ib_udata *udata)#define QEDR_DESTROY_CQ_MAX_ITERATIONS (10)#define QEDR_DESTROY_CQ_ITER_DURATION (10) -void qedr_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) +int qedr_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) {struct qedr_dev *dev =get_qedr_dev (ibcq->device);struct qed_rdma_destroy_cq_out_params oparams;
@@ -1065,7 +1065,7 @@ void qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)/* GSIs CQs are handled by driver, so they don't exist in the FW */ if (cq->cq_type ==QEDR_CQ_TYPE_GSI ) {qedr_db_recovery_del (dev, cq->db_addr, &cq->db.data); -return ; +return 0 ; } iparams.icid = cq->icid;
@@ -1113,6 +1113,7 @@ void qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)* Since the destroy CQ ramrod has also been received on the EQ we can * be certain that there's no event handler in process. */ +return 0 ; } static inline int get_gid_info_from_table(struct ib_qp *ibqp,
drivers/infiniband/hw/qedr/verbs.h +1 -1
@@ -52,7 +52,7 @@ void qedr_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata);int qedr_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata);int qedr_resize_cq (struct ib_cq *,int cqe,struct ib_udata *); -void qedr_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata); +int qedr_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata);int qedr_arm_cq (struct ib_cq *ibcq,enum ib_cq_notify_flags flags);struct ib_qp *qedr_create_qp (struct ib_pd *,struct ib_qp_init_attr *attrs,struct ib_udata *);
drivers/infiniband/hw/usnic/usnic_ib_verbs.c +2 -2
@@ -596,9 +596,9 @@ int usnic_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,return 0 ; } -void usnic_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) +int usnic_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) { -return ; +return 0 ; } struct ib_mr *usnic_ib_reg_mr(struct ib_pd *pd, u64 start, u64 length,
drivers/infiniband/hw/usnic/usnic_ib_verbs.h +1 -1
@@ -60,7 +60,7 @@ int usnic_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata);int usnic_ib_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata); -void usnic_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata); +int usnic_ib_destroy_cq (struct ib_cq *cq,struct ib_udata *udata);struct ib_mr *usnic_ib_reg_mr (struct ib_pd *pd,u64 start,u64 length,u64 virt_addr,int access_flags,struct ib_udata *udata);
drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c +2 -1
@@ -235,7 +235,7 @@ static void pvrdma_free_cq(struct pvrdma_dev *dev, struct pvrdma_cq *cq)* @cq: the completion queue to destroy. * @udata: user data or null for kernel object */ -void pvrdma_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) +int pvrdma_destroy_cq (struct ib_cq *cq,struct ib_udata *udata) {struct pvrdma_cq *vcq =to_vcq (cq);union pvrdma_cmd_req req;
@@ -261,6 +261,7 @@ void pvrdma_destroy_cq(struct ib_cq *cq, struct ib_udata *udata)pvrdma_free_cq (dev, vcq);atomic_dec (&dev->num_cqs); +return 0 ; }static inline struct pvrdma_cqe *get_cqe (struct pvrdma_cq *cq,int i)
drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h +1 -1
@@ -411,7 +411,7 @@ int pvrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, unsigned int *sg_offset);int pvrdma_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata); -void pvrdma_destroy_cq (struct ib_cq *cq,struct ib_udata *udata); +int pvrdma_destroy_cq (struct ib_cq *cq,struct ib_udata *udata);int pvrdma_poll_cq (struct ib_cq *ibcq,int num_entries,struct ib_wc *wc);int pvrdma_req_notify_cq (struct ib_cq *cq,enum ib_cq_notify_flags flags); int pvrdma_create_ah(struct ib_ah *ah, struct rdma_ah_init_attr *init_attr,
drivers/infiniband/sw/rdmavt/cq.c +2 -1
@@ -315,7 +315,7 @@ int rvt_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,* * Called by ib_destroy_cq() in the generic verbs code. */ -void rvt_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) +int rvt_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) {struct rvt_cq *cq =ibcq_to_rvtcq (ibcq);struct rvt_dev_info *rdi = cq->rdi;
@@ -328,6 +328,7 @@ void rvt_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)kref_put (&cq->ip->ref, rvt_release_mmap_info); else vfree(cq->kqueue); +return 0 ; }/**
drivers/infiniband/sw/rdmavt/cq.h +1 -1
@@ -53,7 +53,7 @@int rvt_create_cq (struct ib_cq *ibcq,const struct ib_cq_init_attr *attr,struct ib_udata *udata); -void rvt_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata); +int rvt_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata);int rvt_req_notify_cq (struct ib_cq *ibcq,enum ib_cq_notify_flags notify_flags);int rvt_resize_cq (struct ib_cq *ibcq,int cqe,struct ib_udata *udata);int rvt_poll_cq (struct ib_cq *ibcq,int num_entries,struct ib_wc *entry);
drivers/infiniband/sw/rxe/rxe_verbs.c +2 -1
@@ -816,13 +816,14 @@ static int rxe_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,return rxe_add_to_pool (&rxe->cq_pool, &cq->pelem); } -static void rxe_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) +static int rxe_destroy_cq (struct ib_cq *ibcq,struct ib_udata *udata) {struct rxe_cq *cq =to_rcq (ibcq);rxe_cq_disable (cq);rxe_drop_ref (cq); +return 0 ; }static int rxe_resize_cq (struct ib_cq *ibcq,int cqe,struct ib_udata *udata)
drivers/infiniband/sw/siw/siw_verbs.c +2 -1
@@ -1064,7 +1064,7 @@ int siw_post_receive(struct ib_qp *base_qp, const struct ib_recv_wr *wr,return rv >0 ?0 : rv; } -void siw_destroy_cq (struct ib_cq *base_cq,struct ib_udata *udata) +int siw_destroy_cq (struct ib_cq *base_cq,struct ib_udata *udata) {struct siw_cq *cq =to_siw_cq (base_cq);struct siw_device *sdev =to_siw_dev (base_cq->device);
@@ -1082,6 +1082,7 @@ void siw_destroy_cq(struct ib_cq *base_cq, struct ib_udata *udata)atomic_dec (&sdev->num_cq);vfree (cq->queue); +return 0 ; }/*
drivers/infiniband/sw/siw/siw_verbs.h +1 -1
@@ -63,7 +63,7 @@ int siw_post_send(struct ib_qp *base_qp, const struct ib_send_wr *wr, const struct ib_send_wr **bad_wr);int siw_post_receive (struct ib_qp *base_qp,const struct ib_recv_wr *wr,const struct ib_recv_wr **bad_wr); -void siw_destroy_cq (struct ib_cq *base_cq,struct ib_udata *udata); +int siw_destroy_cq (struct ib_cq *base_cq,struct ib_udata *udata);int siw_poll_cq (struct ib_cq *base_cq,int num_entries,struct ib_wc *wc);int siw_req_notify_cq (struct ib_cq *base_cq,enum ib_cq_notify_flags flags); struct ib_mr *siw_reg_user_mr(struct ib_pd *base_pd, u64 start, u64 len,
include/rdma/ib_verbs.h +4 -2
@@ -2465,7 +2465,7 @@ struct ib_device_ops {int (*create_cq)(struct ib_cq *cq,const struct ib_cq_init_attr *attr,struct ib_udata *udata);int (*modify_cq)(struct ib_cq *cq,u16 cq_count,u16 cq_period); -void (*destroy_cq)(struct ib_cq *cq,struct ib_udata *udata); +int (*destroy_cq)(struct ib_cq *cq,struct ib_udata *udata);int (*resize_cq)(struct ib_cq *cq,int cqe,struct ib_udata *udata);struct ib_mr *(*get_dma_mr)(struct ib_pd *pd,int mr_access_flags); struct ib_mr *(*reg_user_mr)(struct ib_pd *pd, u64 start, u64 length,
@@ -3922,7 +3922,9 @@ int ib_destroy_cq_user(struct ib_cq *cq, struct ib_udata *udata);*/ static inline void ib_destroy_cq (struct ib_cq *cq) { -ib_destroy_cq_user (cq,NULL ); +int ret =ib_destroy_cq_user (cq,NULL ); + +WARN_ONCE (ret,"Destroy of kernel CQ shouldn't fail" ); }/**
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 352/633 RDMA/umem: Fix ib_umem_find_best_pgsz() for mappings that cross a page boundary
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit a40c20dabdf9045270767c75918feb67f0727c89 ]
It is possible for a single SGL to span an aligned boundary, eg if the SGL is
61440 -> 90112
Then the length is 28672, which currently limits the block size to 32k. With a 32k page size the two covering blocks will be:
32768->65536 and 65536->98304
However, the correct answer is a 128K block size which will span the whole 28672 bytes in a single block.
Instead of limiting based on length figure out which high IOVA bits don't change between the start and end addresses. That is the highest useful page size.
--- drivers/infiniband/core/umem.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/infiniband/core/umem.c +7 -2
@@ -156,8 +156,13 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,return 0 ; va = virt; -/* max page size not to exceed MR length */ - mask =roundup_pow_of_two (umem->length); +/* The best result is the smallest page size that results in the minimum +* number of required pages. Compute the largest page size that could +* work based on VA address bits that don't change. +*/ + mask = pgsz_bitmap & +GENMASK (BITS_PER_LONG -1 , +bits_per ((umem->length -1 + virt) ^ virt));/* offset into first SGL */ pgoff = umem->address & ~PAGE_MASK ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 353/633 RDMA/umem: Prevent small pages from being returned by ib_umem_find_best_pgsz()
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 10c75ccb54e4fe548cb16d7ed426d7d709e6ae76 ]
rdma_for_each_block() makes assumptions about how the SGL is constructed that don't work if the block size is below the page size used to to build the SGL.
The rules for umem SGL construction require that the SG's all be PAGE_SIZE aligned and we don't encode the actual byte offset of the VA range inside the SGL using offset and length. So rdma_for_each_block() has no idea where the actual starting/ending point is to compute the first/last block boundary if the starting address should be within a SGL.
Fixing the SGL construction turns out to be really hard, and will be the subject of other patches. For now block smaller pages.
--- drivers/infiniband/core/umem.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/infiniband/core/umem.c +6 -0
@@ -151,6 +151,12 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,dma_addr_t mask;int i; +/* rdma_for_each_block() has a bug if the page size is smaller than the +* page size used to build the umem. For now prevent smaller page sizes +* from being returned. +*/ + pgsz_bitmap &=GENMASK (BITS_PER_LONG -1 ,PAGE_SHIFT ); +/* At minimum, drivers must support PAGE_SIZE or smaller */ if (WARN_ON (!(pgsz_bitmap &GENMASK (PAGE_SHIFT ,0 ))))return 0 ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 354/633 RDMA/qedr: Fix qp structure memory leak
In reply to Greg Kroah-HartmanFrom: Michal Kalderon <[email protected]>
[ Upstream commit 098e345a1a8faaad6e4e54d138773466cecc45d4 ]
The qedr_qp structure wasn't freed when the protocol was RoCE. kmemleak output when running basic RoCE scenario.
unreferenced object 0xffff927ad7e22c00 (size 1024):
comm "ib_send_bw", pid 7082, jiffies 4384133693 (age 274.698s) hex dump (first 32 bytes):
00 b0 cd a2 79 92 ff ff 00 3f a1 a2 79 92 ff ff ....y....?..y...
00 ee 5c dd 80 92 ff ff 00 f6 5c dd 80 92 ff ff ..\.......\.....
backtrace:
[<00000000b2ba0f35>] qedr_create_qp+0xb3/0x6c0 [qedr]
[<00000000e85a43dd>] ib_uverbs_handler_UVERBS_METHOD_QP_CREATE+0x555/0xad0 [ib_uverbs]
[<00000000fee4d029>] ib_uverbs_cmd_verbs+0xa5a/0xb80 [ib_uverbs]
[<000000005d622660>] ib_uverbs_ioctl+0xa4/0x110 [ib_uverbs]
[<00000000eb4cdc71>] ksys_ioctl+0x87/0xc0
[<00000000abe6b23a>] __x64_sys_ioctl+0x16/0x20
[<0000000046e7cef4>] do_syscall_64+0x4d/0x90
[<00000000c6948f76>] entry_SYSCALL_64_after_hwframe+0x44/0xa9--- drivers/infiniband/hw/qedr/verbs.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/infiniband/hw/qedr/verbs.c +2 -0
@@ -2753,6 +2753,8 @@ int qedr_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)if (rdma_protocol_iwarp (&dev->ibdev,1 ))qedr_iw_qp_rem_ref (&qp->ibqp); +else +kfree (qp);return 0 ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 355/633 RDMA/qedr: Fix doorbell setting
In reply to Greg Kroah-HartmanFrom: Michal Kalderon <[email protected]>
[ Upstream commit 0b1eddc1964351cd5ce57aff46853ed4ce9ebbff ]
Change the doorbell setting so that the maximum value between the last and current value is set. This is to avoid doorbells being lost.
--- drivers/infiniband/hw/qedr/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/qedr/verbs.c +1 -1
@@ -998,7 +998,7 @@ int qedr_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,/* Generate doorbell address. */ cq->db.data.icid = cq->icid; cq->db_addr = dev->db_addr + db_offset; - cq->db.data.params =DB_AGG_CMD_SET << + cq->db.data.params =DB_AGG_CMD_MAX <<RDMA_PWM_VAL32_DATA_AGG_CMD_SHIFT ;/* point to the very last element, passing it we will toggle */
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 356/633 RDMA/qedr: Fix use of uninitialized field
In reply to Greg Kroah-HartmanFrom: Michal Kalderon <[email protected]>
[ Upstream commit a379ad54e55a12618cae7f6333fd1b3071de9606 ]
dev->attr.page_size_caps was used uninitialized when setting device attributes
--- drivers/infiniband/hw/qedr/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/qedr/main.c +1 -1
@@ -601,7 +601,7 @@ static int qedr_set_device_attr(struct qedr_dev *dev) qed_attr = dev->ops->rdma_query_device (dev->rdma_ctx);/* Part 2 - check capabilities */ - page_size = ~dev->attr.page_size_caps +1 ; + page_size = ~qed_attr->page_size_caps +1 ;if (page_size >PAGE_SIZE ) { DP_ERR(dev, "Kernel PAGE_SIZE is %ld which is smaller than minimum page size (%d) required by qedr\n",
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 357/633 RDMA/qedr: Fix return code if accept is called on a destroyed qp
In reply to Greg Kroah-HartmanFrom: Michal Kalderon <[email protected]>
[ Upstream commit 8a5a10a1a74465065c75d9de1aa6685e1f1aa117 ]
In iWARP, accept could be called after a QP is already destroyed. In this case an error should be returned and not success.
--- drivers/infiniband/hw/qedr/qedr_iw_cm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/infiniband/hw/qedr/qedr_iw_cm.c +4 -2
@@ -736,7 +736,7 @@ int qedr_iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)struct qedr_dev *dev = ep->dev;struct qedr_qp *qp;struct qed_iwarp_accept_in params; -int rc =0 ; +int rc;DP_DEBUG (dev,QEDR_MSG_IWARP ,"Accept on qpid=%d\n" , conn_param->qpn);
@@ -759,8 +759,10 @@ int qedr_iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) params.ord = conn_param->ord;if (test_and_set_bit (QEDR_IWARP_CM_WAIT_FOR_CONNECT , - &qp->iwarp_cm_flags)) + &qp->iwarp_cm_flags)) { + rc = -EINVAL ; goto err;/* QP already destroyed */ + } rc = dev->ops->iwarp_accept (dev->rdma_ctx, ¶ms);if (rc) {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 358/633 RDMA/qedr: Fix inline size returned for iWARP
In reply to Greg Kroah-HartmanFrom: Michal Kalderon <[email protected]>
[ Upstream commit fbf58026b2256e9cd5f241a4801d79d3b2b7b89d ]
commit 59e8970b3798 ("RDMA/qedr: Return max inline data in QP query result") changed query_qp max_inline size to return the max roce inline size. When iwarp was introduced, this should have been modified to return the max inline size based on protocol. This size is cached in the device attributes
--- drivers/infiniband/hw/qedr/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/qedr/verbs.c +1 -1
@@ -2637,7 +2637,7 @@ int qedr_query_qp(struct ib_qp *ibqp, qp_attr->cap.max_recv_wr = qp->rq.max_wr; qp_attr->cap.max_send_sge = qp->sq.max_sges; qp_attr->cap.max_recv_sge = qp->rq.max_sges; - qp_attr->cap.max_inline_data =ROCE_REQ_MAX_INLINE_DATA_SIZE ; + qp_attr->cap.max_inline_data = dev->attr.max_inline; qp_init_attr->cap = qp_attr->cap; qp_attr->ah_attr.type =RDMA_AH_ATTR_TYPE_ROCE ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 359/633 powerpc/pseries/svm: Allocate SWIOTLB buffer anywhere in memory
In reply to Greg Kroah-HartmanFrom: Thiago Jung Bauermann <[email protected]>
[ Upstream commit eae9eec476d13fad9af6da1f44a054ee02b7b161 ]
POWER secure guests (i.e., guests which use the Protected Execution Facility) need to use SWIOTLB to be able to do I/O with the hypervisor, but they don't need the SWIOTLB memory to be in low addresses since the hypervisor doesn't have any addressing limitation.
This solves a SWIOTLB initialization problem we are seeing in secure guests with 128 GB of RAM: they are configured with 4 GB of crashkernel reserved memory, which leaves no space for SWIOTLB in low addresses.
To do this, we use mostly the same code as swiotlb_init(), but allocate the buffer using memblock_alloc() instead of memblock_alloc_low().
--- arch/powerpc/include/asm/svm.h | 4 ++++ arch/powerpc/mm/mem.c | 6 +++++- arch/powerpc/platforms/pseries/svm.c | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-)
arch/powerpc/include/asm/svm.h +4 -0
@@ -15,6 +15,8 @@ static inline bool is_secure_guest(void)return mfmsr () &MSR_S ; } +void __init svm_swiotlb_init (void ); +void dtl_cache_ctor (void *addr);#define get_dtl_cache_ctor () (is_secure_guest() ? dtl_cache_ctor : NULL)
@@ -25,6 +27,8 @@ static inline bool is_secure_guest(void) return false; } +static inline void svm_swiotlb_init (void ) {} +#define get_dtl_cache_ctor () NULL#endif /* CONFIG_PPC_SVM */
arch/powerpc/mm/mem.c +5 -1
@@ -50,6 +50,7 @@#include <asm/swiotlb.h> #include <asm/rtas.h> #include <asm/kasan.h> +#include <asm/svm.h> #include <mm/mmu_decl.h>
@@ -290,7 +291,10 @@ void __init mem_init(void)* back to to-down. */ memblock_set_bottom_up (true); -swiotlb_init (0 ); +if (is_secure_guest ()) +svm_swiotlb_init (); +else +swiotlb_init (0 );#endif high_memory = (void *)__va (max_low_pfn *PAGE_SIZE );
arch/powerpc/platforms/pseries/svm.c +26 -0
@@ -7,6 +7,7 @@*/ #include <linux/mm.h> +#include <linux/memblock.h> #include <asm/machdep.h> #include <asm/svm.h> #include <asm/swiotlb.h>
@@ -34,6 +35,31 @@ static int __init init_svm(void) }machine_early_initcall (pseries, init_svm); +/* +* Initialize SWIOTLB. Essentially the same as swiotlb_init(), except that it +* can allocate the buffer anywhere in memory. Since the hypervisor doesn't have +* any addressing limitation, we don't need to allocate it in low addresses. +*/ +void __init svm_swiotlb_init (void ) +{ +unsigned char *vstart; +unsigned long bytes, io_tlb_nslabs; + + io_tlb_nslabs = (swiotlb_size_or_default () >>IO_TLB_SHIFT ); + io_tlb_nslabs =ALIGN (io_tlb_nslabs,IO_TLB_SEGSIZE ); + + bytes = io_tlb_nslabs <<IO_TLB_SHIFT ; + + vstart =memblock_alloc (PAGE_ALIGN (bytes),PAGE_SIZE ); +if (vstart && !swiotlb_init_with_tbl (vstart, io_tlb_nslabs, false)) +return ; + +if (io_tlb_start) +memblock_free_early (io_tlb_start, +PAGE_ALIGN (io_tlb_nslabs <<IO_TLB_SHIFT )); +panic ("SVM: Cannot allocate SWIOTLB buffer" ); +} +int set_memory_encrypted (unsigned long addr,int numpages) {if (!PAGE_ALIGNED (addr))
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 360/633 powerpc/watchpoint: Fix quadword instruction handling on p10 predecessors
In reply to Greg Kroah-HartmanFrom: Ravi Bangoria <[email protected]>
[ Upstream commit 4759c11ed20454b7b36db4ec15f7d5aa1519af4a ]
On p10 predecessors, watchpoint with quadword access is compared at quadword length. If the watch range is doubleword or less than that in a first half of quadword aligned 16 bytes, and if there is any unaligned quadword access which will access only the 2nd half, the handler should consider it as extraneous and emulate/single-step it before continuing.
--- arch/powerpc/include/asm/hw_breakpoint.h | 1 + arch/powerpc/kernel/hw_breakpoint.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-)
arch/powerpc/include/asm/hw_breakpoint.h +1 -0
@@ -40,6 +40,7 @@ struct arch_hw_breakpoint {#else #define HW_BREAKPOINT_SIZE 0x8#endif +#define HW_BREAKPOINT_SIZE_QUADWORD 0x10#define DABR_MAX_LEN 8#define DAWR_MAX_LEN 512
arch/powerpc/kernel/hw_breakpoint.c +10 -2
@@ -519,9 +519,17 @@ static bool ea_hw_range_overlaps(unsigned long ea, int size, struct arch_hw_breakpoint *info) {unsigned long hw_start_addr, hw_end_addr; +unsigned long align_size =HW_BREAKPOINT_SIZE ; - hw_start_addr =ALIGN_DOWN (info->address,HW_BREAKPOINT_SIZE ); - hw_end_addr =ALIGN (info->address + info->len,HW_BREAKPOINT_SIZE ); +/* +* On p10 predecessors, quadword is handle differently then +* other instructions. +*/ +if (!cpu_has_feature (CPU_FTR_ARCH_31 ) && size ==16 ) + align_size =HW_BREAKPOINT_SIZE_QUADWORD ; + + hw_start_addr =ALIGN_DOWN (info->address, align_size); + hw_end_addr =ALIGN (info->address + info->len, align_size);return ((ea < hw_end_addr) && (ea + size > hw_start_addr)); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 361/633 powerpc/watchpoint: Fix handling of vector instructions
In reply to Greg Kroah-HartmanFrom: Ravi Bangoria <[email protected]>
[ Upstream commit 4441eb02333a9b46a0d919aa7a6d3b137b5f2562 ]
Vector load/store instructions are special because they are always aligned. Thus unaligned EA needs to be aligned down before comparing it with watch ranges. Otherwise we might consider valid event as invalid.
--- arch/powerpc/kernel/hw_breakpoint.c | 2 ++ 1 file changed, 2 insertions(+)
arch/powerpc/kernel/hw_breakpoint.c +2 -0
@@ -643,6 +643,8 @@ static void get_instr_detail(struct pt_regs *regs, struct ppc_inst *instr,if (*type ==CACHEOP ) { *size =cache_op_size (); *ea &= ~(*size -1 ); + }else if (*type ==LOAD_VMX || *type ==STORE_VMX ) { + *ea &= ~(*size -1 ); } }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 362/633 powerpc/watchpoint: Add hw_len wherever missing
In reply to Greg Kroah-HartmanFrom: Ravi Bangoria <[email protected]>
[ Upstream commit 58da5984d2ea6d95f3f9d9e8dd9f7e1b0dddfb3c ]
There are couple of places where we set len but not hw_len. For ptrace/perf watchpoints, when CONFIG_HAVE_HW_BREAKPOINT=Y, hw_len will be calculated and set internally while parsing watchpoint. But when CONFIG_HAVE_HW_BREAKPOINT=N, we need to manually set 'hw_len'. Similarly for xmon as well, hw_len needs to be set directly.
--- arch/powerpc/kernel/ptrace/ptrace-noadv.c | 1 + arch/powerpc/xmon/xmon.c | 1 + 2 files changed, 2 insertions(+)
arch/powerpc/kernel/ptrace/ptrace-noadv.c +1 -0
@@ -219,6 +219,7 @@ long ppc_set_hwdebug(struct task_struct *child, struct ppc_hw_breakpoint *bp_inf brk.address =ALIGN_DOWN (bp_info->addr,HW_BREAKPOINT_SIZE ); brk.type =HW_BRK_TYPE_TRANSLATE ; brk.len =DABR_MAX_LEN ; + brk.hw_len =DABR_MAX_LEN ;if (bp_info->trigger_type &PPC_BREAKPOINT_TRIGGER_READ ) brk.type |=HW_BRK_TYPE_READ ;if (bp_info->trigger_type &PPC_BREAKPOINT_TRIGGER_WRITE )
arch/powerpc/xmon/xmon.c +1 -0
@@ -962,6 +962,7 @@ static void insert_cpu_bpts(void) brk.address = dabr[i].address; brk.type = (dabr[i].enabled &HW_BRK_TYPE_DABR ) |HW_BRK_TYPE_PRIV_ALL ; brk.len =8 ; + brk.hw_len =8 ;__set_breakpoint (i, &brk); } }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 363/633 powerpc/book3s64/hash/4k: Support large linear mapping range with 4K
In reply to Greg Kroah-HartmanFrom: Aneesh Kumar K.V <[email protected]>
[ Upstream commit 7746406baa3bc9e23fdd7b7da2f04d86e25ab837 ]
With commit: 0034d395f89d ("powerpc/mm/hash64: Map all the kernel regions in the same 0xc range"), we now split the 64TB address range into 4 contexts each of 16TB. That implies we can do only 16TB linear mapping.
On some systems, eg. Power9, memory attached to nodes > 0 will appear above 16TB in the linear mapping. This resulted in kernel crash when we boot such systems in hash translation mode with 4K PAGE_SIZE.
This patch updates the kernel mapping such that we now start supporting upto 61TB of memory with 4K. The kernel mapping now looks like below 4K PAGE_SIZE and hash translation.
vmalloc start = 0xc0003d0000000000
IO start = 0xc0003e0000000000
vmemmap start = 0xc0003f0000000000Our MAX_PHYSMEM_BITS for 4K is still 64TB even though we can only map 61TB. We prevent bolt mapping anything outside 61TB range by checking against H_VMALLOC_START.
--- arch/powerpc/include/asm/book3s/64/hash-4k.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
arch/powerpc/include/asm/book3s/64/hash-4k.h +6 -7
@@ -13,20 +13,19 @@*/ #define MAX_EA_BITS_PER_CONTEXT 46 -#define REGION_SHIFT (MAX_EA_BITS_PER_CONTEXT - 2)/* -* Our page table limit us to 64TB. Hence for the kernel mapping, -* each MAP area is limited to 16 TB. -* The four map areas are: linear mapping, vmap, IO and vmemmap +* Our page table limit us to 64TB. For 64TB physical memory, we only need 64GB +* of vmemmap space. To better support sparse memory layout, we use 61TB +* linear map range, 1TB of vmalloc, 1TB of I/O and 1TB of vmememmap. */ +#define REGION_SHIFT (40)#define H_KERN_MAP_SIZE (ASM_CONST(1) << REGION_SHIFT)/* -* Define the address range of the kernel non-linear virtual area -* 16TB +* Define the address range of the kernel non-linear virtual area (61TB) */ -#define H_KERN_VIRT_START ASM_CONST(0xc000100000000000) +#define H_KERN_VIRT_START ASM_CONST(0xc0003d0000000000)#ifndef __ASSEMBLY__#define H_PTE_TABLE_SIZE (sizeof(pte_t) << H_PTE_INDEX_SIZE)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 364/633 powerpc/tau: Use appropriate temperature sample interval
In reply to Greg Kroah-HartmanFrom: Finn Thain <[email protected]>
[ Upstream commit 66943005cc41f48e4d05614e8f76c0ca1812f0fd ]
According to the MPC750 Users Manual, the SITV value in Thermal Management Register 3 is 13 bits long. The present code calculates the SITV value as 60 * 500 cycles. This would overflow to give 10 us on a 500 MHz CPU rather than the intended 60 us. (But according to the Microprocessor Datasheet, there is also a factor of 266 that has to be applied to this value on certain parts i.e. speed sort above 266 MHz.) Always use the maximum cycle count, as recommended by the Datasheet.
--- arch/powerpc/include/asm/reg.h | 2 +- arch/powerpc/kernel/tau_6xx.c | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-)
arch/powerpc/include/asm/reg.h +1 -1
@@ -815,7 +815,7 @@#define THRM1_TIN (1 << 31)#define THRM1_TIV (1 << 30)#define THRM1_THRES (x) ((x&0x7f)<<23) -#define THRM3_SITV (x) ((x&0x3fff)<<1) +#define THRM3_SITV (x) ((x & 0x1fff) << 1)#define THRM1_TID (1<<2)#define THRM1_TIE (1<<1)#define THRM1_V (1<<0)
arch/powerpc/kernel/tau_6xx.c +4 -8
@@ -178,15 +178,11 @@ static void tau_timeout(void * info)* complex sleep code needs to be added. One mtspr every time * tau_timeout is called is probably not a big deal. * -* Enable thermal sensor and set up sample interval timer -* need 20 us to do the compare.. until a nice 'cpu_speed' function -* call is implemented, just assume a 500 mhz clock. It doesn't really -* matter if we take too long for a compare since it's all interrupt -* driven anyway. -* -* use a extra long time.. (60 us @ 500 mhz) +* The "PowerPC 740 and PowerPC 750 Microprocessor Datasheet" +* recommends that "the maximum value be set in THRM3 under all +* conditions." */ -mtspr (SPRN_THRM3 ,THRM3_SITV (500 *60 ) |THRM3_E ); +mtspr (SPRN_THRM3 ,THRM3_SITV (0x1fff ) |THRM3_E );local_irq_restore (flags); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 365/633 powerpc/tau: Convert from timer to workqueue
In reply to Greg Kroah-HartmanFrom: Finn Thain <[email protected]>
[ Upstream commit b1c6a0a10bfaf36ec82fde6f621da72407fa60a1 ]
Since commit 19dbdcb8039cf ("smp: Warn on function calls from softirq context") the Thermal Assist Unit driver causes a warning like the following when CONFIG_SMP is enabled.
------------[ cut here ]------------
WARNING: CPU: 0 PID: 0 at kernel/smp.c:428 smp_call_function_many_cond+0xf4/0x38c
Modules linked in:
CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.7.0-pmac #3
NIP: c00b37a8 LR: c00b3abc CTR: c001218c
REGS: c0799c60 TRAP: 0700 Not tainted (5.7.0-pmac)
MSR: 00029032 <EE,ME,IR,DR,RI> CR: 42000224 XER: 00000000
GPR00: c00b3abc c0799d18 c076e300 c079ef5c c0011fec 00000000 00000000 00000000
GPR08: 00000100 00000100 00008000 ffffffff 42000224 00000000 c079d040 c079d044
GPR16: 00000001 00000000 00000004 c0799da0 c079f054 c07a0000 c07a0000 00000000
GPR24: c0011fec 00000000 c079ef5c c079ef5c 00000000 00000000 00000000 00000000
NIP [c00b37a8] smp_call_function_many_cond+0xf4/0x38c
LR [c00b3abc] on_each_cpu+0x38/0x68
Call Trace:
[c0799d18] [ffffffff] 0xffffffff (unreliable)
[c0799d68] [c00b3abc] on_each_cpu+0x38/0x68
[c0799d88] [c0096704] call_timer_fn.isra.26+0x20/0x7c
[c0799d98] [c0096b40] run_timer_softirq+0x1d4/0x3fc
[c0799df8] [c05b4368] __do_softirq+0x118/0x240
[c0799e58] [c0039c44] irq_exit+0xc4/0xcc
[c0799e68] [c000ade8] timer_interrupt+0x1b0/0x230
[c0799ea8] [c0013520] ret_from_except+0x0/0x14
--- interrupt: 901 at arch_cpu_idle+0x24/0x6c
LR = arch_cpu_idle+0x24/0x6c
[c0799f70] [00000001] 0x1 (unreliable)
[c0799f80] [c0060990] do_idle+0xd8/0x17c
[c0799fa0] [c0060ba8] cpu_startup_entry+0x24/0x28
[c0799fb0] [c072d220] start_kernel+0x434/0x44c
[c0799ff0] [00003860] 0x3860
Instruction dump:
8129f204 2f890000 40beff98 3d20c07a 8929eec4 2f890000 40beff88 0fe00000
81220000 552805de 550802ef 4182ff84 <0fe00000> 3860ffff 7f65db78 7f44d378
---[ end trace 34a886e47819c2eb ]---Don't call on_each_cpu() from a timer callback, call it from a worker thread instead.
--- arch/powerpc/kernel/tau_6xx.c | 38 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 20 deletions(-)
arch/powerpc/kernel/tau_6xx.c +18 -20
@@ -13,13 +13,14 @@*/ #include <linux/errno.h> -#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/param.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/delay.h> +#include <linux/workqueue.h> #include <asm/io.h> #include <asm/reg.h>
@@ -39,8 +40,6 @@ static struct tau_tempunsigned char grew; } tau[NR_CPUS ]; -struct timer_list tau_timer; -#undef DEBUG/* TODO: put these in a /proc interface, with some sanity checks, and maybe
@@ -50,7 +49,7 @@ struct timer_list tau_timer;#define step_size 2/* step size when temp goes out of range */ #define window_expand 1/* expand the window by this much */ /* configurable values for shrinking the window */ -#define shrink_timer 2*HZ/* period between shrinking the window */ +#define shrink_timer 2000/* period between shrinking the window */ #define min_window 2/* minimum window size, degrees C */ static void set_thresholds (unsigned long cpu)
@@ -187,14 +186,18 @@ static void tau_timeout(void * info)local_irq_restore (flags); } -static void tau_timeout_smp (struct timer_list *unused) -{ +static struct workqueue_struct *tau_workq; -/* schedule ourselves to be run again */ -mod_timer (&tau_timer, jiffies + shrink_timer) ; +static void tau_work_func (struct work_struct *work) +{ +msleep (shrink_timer);on_each_cpu (tau_timeout,NULL ,0 ); +/* schedule ourselves to be run again */ +queue_work (tau_workq, work); } +DECLARE_WORK (tau_work, tau_work_func); +/* * setup the TAU *
@@ -227,21 +230,16 @@ static int __init TAU_init(void)return 1 ; } - -/* first, set up the window shrinking timer */ -timer_setup (&tau_timer, tau_timeout_smp,0 ); - tau_timer.expires = jiffies + shrink_timer; -add_timer (&tau_timer); + tau_workq =alloc_workqueue ("tau" ,WQ_UNBOUND ,1 ,0 ); +if (!tau_workq) +return -ENOMEM ;on_each_cpu (TAU_init_smp,NULL ,0 ); -printk ("Thermal assist unit " ); -#ifdef CONFIG_TAU_INT -printk ("using interrupts, " ); -#else -printk ("using timers, " ); -#endif -printk ("shrink_timer: %d jiffies\n" , shrink_timer); +queue_work (tau_workq, &tau_work); + +pr_info ("Thermal assist unit using %s, shrink_timer: %d ms\n" , +IS_ENABLED (CONFIG_TAU_INT ) ?"interrupts" :"workqueue" , shrink_timer); tau_initialized =1 ;return 0 ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 366/633 powerpc/tau: Remove duplicated set_thresholds() call
In reply to Greg Kroah-HartmanFrom: Finn Thain <[email protected]>
[ Upstream commit 420ab2bc7544d978a5d0762ee736412fe9c796ab ]
The commentary at the call site seems to disagree with the code. The conditional prevents calling set_thresholds() via the exception handler, which appears to crash. Perhaps that's because it immediately triggers another TAU exception. Anyway, calling set_thresholds() from TAUupdate() is redundant because tau_timeout() does so.
--- arch/powerpc/kernel/tau_6xx.c | 5 ----- 1 file changed, 5 deletions(-)
arch/powerpc/kernel/tau_6xx.c +0 -5
@@ -110,11 +110,6 @@ static void TAUupdate(int cpu)#ifdef DEBUG printk ("grew = %d\n" , tau[cpu].grew);#endif - -#ifndef CONFIG_TAU_INT /* tau_timeout will do this if not using interrupts */ -set_thresholds (cpu); -#endif - }#ifdef CONFIG_TAU_INT
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 367/633 powerpc/tau: Check processor type before enabling TAU interrupt
In reply to Greg Kroah-HartmanFrom: Finn Thain <[email protected]>
[ Upstream commit 5e3119e15fed5b9a9a7e528665ff098a4a8dbdbc ]
According to Freescale's documentation, MPC74XX processors have an erratum that prevents the TAU interrupt from working, so don't try to use it when running on those processors.
--- arch/powerpc/kernel/tau_6xx.c | 33 ++++++++++++++------------------- arch/powerpc/platforms/Kconfig | 5 ++--- 2 files changed, 16 insertions(+), 22 deletions(-)
arch/powerpc/kernel/tau_6xx.c +14 -19
@@ -40,6 +40,8 @@ static struct tau_tempunsigned char grew; } tau[NR_CPUS ]; +static bool tau_int_enable; +#undef DEBUG/* TODO: put these in a /proc interface, with some sanity checks, and maybe
@@ -54,22 +56,13 @@ static struct tau_tempstatic void set_thresholds (unsigned long cpu) { -#ifdef CONFIG_TAU_INT -/* -* setup THRM1, -* threshold, valid bit, enable interrupts, interrupt when below threshold -*/ -mtspr (SPRN_THRM1 ,THRM1_THRES (tau[cpu].low) |THRM1_V |THRM1_TIE |THRM1_TID ); +u32 maybe_tie = tau_int_enable ?THRM1_TIE :0 ; -/* setup THRM2, -* threshold, valid bit, enable interrupts, interrupt when above threshold -*/ -mtspr (SPRN_THRM2 ,THRM1_THRES (tau[cpu].high) |THRM1_V |THRM1_TIE ); -#else -/* same thing but don't enable interrupts */ -mtspr (SPRN_THRM1 ,THRM1_THRES (tau[cpu].low) |THRM1_V |THRM1_TID ); -mtspr (SPRN_THRM2 ,THRM1_THRES (tau[cpu].high) |THRM1_V ); -#endif +/* setup THRM1, threshold, valid bit, interrupt when below threshold */ +mtspr (SPRN_THRM1 ,THRM1_THRES (tau[cpu].low) |THRM1_V | maybe_tie |THRM1_TID ); + +/* setup THRM2, threshold, valid bit, interrupt when above threshold */ +mtspr (SPRN_THRM2 ,THRM1_THRES (tau[cpu].high) |THRM1_V | maybe_tie); }static void TAUupdate (int cpu)
@@ -142,9 +135,8 @@ static void tau_timeout(void * info)local_irq_save (flags); cpu =smp_processor_id (); -#ifndef CONFIG_TAU_INT -TAUupdate (cpu); -#endif +if (!tau_int_enable) +TAUupdate (cpu); size = tau[cpu].high - tau[cpu].low;if (size > min_window && ! tau[cpu].grew) {
@@ -225,6 +217,9 @@ static int __init TAU_init(void)return 1 ; } + tau_int_enable =IS_ENABLED (CONFIG_TAU_INT ) && + !strcmp (cur_cpu_spec->platform,"ppc750" ); + tau_workq =alloc_workqueue ("tau" ,WQ_UNBOUND ,1 ,0 );if (!tau_workq)return -ENOMEM ;
@@ -234,7 +229,7 @@ static int __init TAU_init(void)queue_work (tau_workq, &tau_work);pr_info ("Thermal assist unit using %s, shrink_timer: %d ms\n" , -IS_ENABLED (CONFIG_TAU_INT ) ?"interrupts" :"workqueue" , shrink_timer); + tau_int_enable ?"interrupts" :"workqueue" , shrink_timer); tau_initialized =1 ;return 0 ;
arch/powerpc/platforms/Kconfig +2 -3
@@ -223,9 +223,8 @@ config TAU temperature within 2-4 degrees Celsius. This option shows the current on-die temperature in /proc/cpuinfo if the cpu supports it. - Unfortunately, on some chip revisions, this sensor is very inaccurate - and in many cases, does not work at all, so don't assume the cpu - temp is actually what /proc/cpuinfo says it is. + Unfortunately, this sensor is very inaccurate when uncalibrated, so + don't assume the cpu temp is actually what /proc/cpuinfo says it is. config TAU_INT bool "Interrupt driven TAU driver (DANGEROUS)"
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 368/633 powerpc/tau: Disable TAU between measurements
In reply to Greg Kroah-HartmanFrom: Finn Thain <[email protected]>
[ Upstream commit e63d6fb5637e92725cf143559672a34b706bca4f ]
Enabling CONFIG_TAU_INT causes random crashes:
Unrecoverable exception 1700 at c0009414 (msr=1000)
Oops: Unrecoverable exception, sig: 6 [#1] BE PAGE_SIZE=4K MMU=Hash SMP NR_CPUS=2 PowerMac Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.7.0-pmac-00043-gd5f545e1a8593 #5 NIP: c0009414 LR: c0009414 CTR: c00116fc REGS: c0799eb8 TRAP: 1700 Not tainted (5.7.0-pmac-00043-gd5f545e1a8593) MSR: 00001000 <ME> CR: 22000228 XER: 00000100
GPR00: 00000000 c0799f70 c076e300 00800000 0291c0ac 00e00000 c076e300 00049032
GPR08: 00000001 c00116fc 00000000 dfbd3200 ffffffff 007f80a8 00000000 00000000
GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 c075ce04
GPR24: c075ce04 dfff8880 c07b0000 c075ce04 00080000 00000001 c079ef98 c079ef5c NIP [c0009414] arch_cpu_idle+0x24/0x6c
LR [c0009414] arch_cpu_idle+0x24/0x6c
Call Trace:
[c0799f70] [00000001] 0x1 (unreliable)
[c0799f80] [c0060990] do_idle+0xd8/0x17c
[c0799fa0] [c0060ba4] cpu_startup_entry+0x20/0x28
[c0799fb0] [c072d220] start_kernel+0x434/0x44c
[c0799ff0] [00003860] 0x3860
Instruction dump:
XXXXXXXX XXXXXXXX XXXXXXXX 3d20c07b XXXXXXXX XXXXXXXX XXXXXXXX 7c0802a6 XXXXXXXX XXXXXXXX XXXXXXXX 4e800421 XXXXXXXX XXXXXXXX XXXXXXXX 7d2000a6
---[ end trace 3a0c9b5cb216db6b ]---
Resolve this problem by disabling each THRMn comparator when handling the associated THRMn interrupt and by disabling the TAU entirely when updating THRMn thresholds.
--- arch/powerpc/kernel/tau_6xx.c | 65 +++++++++++++--------------------- arch/powerpc/platforms/Kconfig | 9 ++--- 2 files changed, 26 insertions(+), 48 deletions(-)
arch/powerpc/kernel/tau_6xx.c +24 -41
@@ -42,8 +42,6 @@ static struct tau_tempstatic bool tau_int_enable; -#undef DEBUG -/* TODO: put these in a /proc interface, with some sanity checks, and maybe * dynamic adjustment to minimize # of interrupts */ /* configurable values for step size and how much to expand the window when
@@ -67,42 +65,33 @@ static void set_thresholds(unsigned long cpu)static void TAUupdate (int cpu) { -unsigned thrm; - -#ifdef DEBUG -printk ("TAUupdate " ); -#endif +u32 thrm; +u32 bits =THRM1_TIV |THRM1_TIN |THRM1_V ;/* if both thresholds are crossed, the step_sizes cancel out * and the window winds up getting expanded twice. */ -if ((thrm =mfspr (SPRN_THRM1 )) &THRM1_TIV ){/* is valid? */ -if (thrm &THRM1_TIN ){/* crossed low threshold */ -if (tau[cpu].low >= step_size){ - tau[cpu].low -= step_size; - tau[cpu].high -= (step_size - window_expand); - } - tau[cpu].grew =1 ; -#ifdef DEBUG -printk ("low threshold crossed " ); -#endif + thrm =mfspr (SPRN_THRM1 ); +if ((thrm & bits) == bits) { +mtspr (SPRN_THRM1 ,0 ); + +if (tau[cpu].low >= step_size) { + tau[cpu].low -= step_size; + tau[cpu].high -= (step_size - window_expand); } + tau[cpu].grew =1 ; +pr_debug ("%s: low threshold crossed\n" , __func__); } -if ((thrm =mfspr (SPRN_THRM2 )) &THRM1_TIV ){/* is valid? */ -if (thrm &THRM1_TIN ){/* crossed high threshold */ -if (tau[cpu].high <=127 -step_size){ - tau[cpu].low += (step_size - window_expand); - tau[cpu].high += step_size; - } - tau[cpu].grew =1 ; -#ifdef DEBUG -printk ("high threshold crossed " ); -#endif + thrm =mfspr (SPRN_THRM2 ); +if ((thrm & bits) == bits) { +mtspr (SPRN_THRM2 ,0 ); + +if (tau[cpu].high <=127 - step_size) { + tau[cpu].low += (step_size - window_expand); + tau[cpu].high += step_size; } + tau[cpu].grew =1 ; +pr_debug ("%s: high threshold crossed\n" , __func__); } - -#ifdef DEBUG -printk ("grew = %d\n" , tau[cpu].grew); -#endif }#ifdef CONFIG_TAU_INT
@@ -127,17 +116,17 @@ void TAUException(struct pt_regs * regs)static void tau_timeout (void * info) {int cpu; -unsigned long flags;int size;int shrink; -/* disabling interrupts *should* be okay */ -local_irq_save (flags); cpu =smp_processor_id ();if (!tau_int_enable)TAUupdate (cpu); +/* Stop thermal sensor comparisons and interrupts */ +mtspr (SPRN_THRM3 ,0 ); + size = tau[cpu].high - tau[cpu].low;if (size > min_window && ! tau[cpu].grew) {/* do an exponential shrink of half the amount currently over size */
@@ -159,18 +148,12 @@ static void tau_timeout(void * info)set_thresholds (cpu); -/* -* Do the enable every time, since otherwise a bunch of (relatively) -* complex sleep code needs to be added. One mtspr every time -* tau_timeout is called is probably not a big deal. -* +/* Restart thermal sensor comparisons and interrupts. * The "PowerPC 740 and PowerPC 750 Microprocessor Datasheet" * recommends that "the maximum value be set in THRM3 under all * conditions." */ mtspr (SPRN_THRM3 ,THRM3_SITV (0x1fff ) |THRM3_E ); - -local_irq_restore (flags); }static struct workqueue_struct *tau_workq;
arch/powerpc/platforms/Kconfig +2 -7
@@ -227,7 +227,7 @@ config TAU don't assume the cpu temp is actually what /proc/cpuinfo says it is. config TAU_INT - bool "Interrupt driven TAU driver (DANGEROUS)" + bool "Interrupt driven TAU driver (EXPERIMENTAL)" depends on TAU help The TAU supports an interrupt driven mode which causes an interrupt
@@ -235,12 +235,7 @@ config TAU_INT to get notified the temp has exceeded a range. With this option off, a timer is used to re-check the temperature periodically. - However, on some cpus it appears that the TAU interrupt hardware - is buggy and can cause a situation which would lead unexplained hard - lockups. - - Unless you are extending the TAU driver, or enjoy kernel/hardware - debugging, leave this option off. + If in doubt, say N here. config TAU_AVERAGE bool "Average high and low temp"
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 369/633 powerpc/kasan: Fix CONFIG_KASAN_VMALLOC for 8xx
In reply to Greg Kroah-HartmanFrom: Christophe Leroy <[email protected]>
[ Upstream commit 4c42dc5c69a8f24c467a6c997909d2f1d4efdc7f ]
Before the commit identified below, pages tables allocation was performed after the allocation of final shadow area for linear memory. But that commit switched the order, leading to page tables being already allocated at the time 8xx kasan_init_shadow_8M() is called. Due to this, kasan_init_shadow_8M() doesn't map the needed shadow entries because there are already page tables.
kasan_init_shadow_8M() installs huge PMD entries instead of page tables. We could at that time free the page tables, but there is no point in creating page tables that get freed before being used.
Only book3s/32 hash needs early allocation of page tables. For other variants, we can keep the initial order and create remaining page tables after the allocation of final shadow memory for linear mem.
Move back the allocation of shadow page tables for CONFIG_KASAN_VMALLOC into kasan_init() after the loop which creates final shadow memory for linear mem.
--- arch/powerpc/mm/kasan/kasan_init_32.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/powerpc/mm/kasan/kasan_init_32.c +9 -3
@@ -121,8 +121,7 @@ void __init kasan_mmu_init(void) {int ret; -if (early_mmu_has_feature (MMU_FTR_HPTE_TABLE ) || -IS_ENABLED (CONFIG_KASAN_VMALLOC )) { +if (early_mmu_has_feature (MMU_FTR_HPTE_TABLE )) { ret =kasan_init_shadow_page_tables (KASAN_SHADOW_START ,KASAN_SHADOW_END );if (ret)
@@ -133,11 +132,11 @@ void __init kasan_mmu_init(void)void __init kasan_init (void ) {struct memblock_region *reg; +int ret;for_each_memblock (memory, reg) {phys_addr_t base = reg->base;phys_addr_t top =min (base + reg->size, total_lowmem); -int ret;if (base >= top)continue ;
@@ -147,6 +146,13 @@ void __init kasan_init(void)panic ("kasan: kasan_init_region() failed" ); } +if (IS_ENABLED (CONFIG_KASAN_VMALLOC )) { + ret =kasan_init_shadow_page_tables (KASAN_SHADOW_START ,KASAN_SHADOW_END ); + +if (ret) +panic ("kasan: kasan_init_shadow_page_tables() failed" ); + } +kasan_remap_early_shadow_ro ();clear_page (kasan_early_shadow_page);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 370/633 powerpc/64s/radix: Fix mm_cpumask trimming race vs kthread_use_mm
In reply to Greg Kroah-HartmanFrom: Nicholas Piggin <[email protected]>
[ Upstream commit a665eec0a22e11cdde708c1c256a465ebe768047 ]
Commit 0cef77c7798a7 ("powerpc/64s/radix: flush remote CPUs out of single-threaded mm_cpumask") added a mechanism to trim the mm_cpumask of a process under certain conditions. One of the assumptions is that mm_users would not be incremented via a reference outside the process context with mmget_not_zero() then go on to kthread_use_mm() via that reference.
That invariant was broken by io_uring code (see previous sparc64 fix), but I'll point Fixes: to the original powerpc commit because we are changing that assumption going forward, so this will make backports match up.
Fix this by no longer relying on that assumption, but by having each CPU check the mm is not being used, and clearing their own bit from the mask only if it hasn't been switched-to by the time the IPI is processed.
This relies on commit 38cf307c1f20 ("mm: fix kthread_use_mm() vs TLB invalidate") and ARCH_WANT_IRQS_OFF_ACTIVATE_MM to disable irqs over mm switch sequences.
Depends-on: 38cf307c1f20 ("mm: fix kthread_use_mm() vs TLB invalidate")
--- arch/powerpc/include/asm/tlb.h | 13 ------------- arch/powerpc/mm/book3s64/radix_tlb.c | 23 ++++++++++++++++------- 2 files changed, 16 insertions(+), 20 deletions(-)
arch/powerpc/include/asm/tlb.h +0 -13
@@ -67,19 +67,6 @@ static inline int mm_is_thread_local(struct mm_struct *mm)return false; return cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)); } -static inline void mm_reset_thread_local (struct mm_struct *mm) -{ -WARN_ON (atomic_read (&mm->context.copros) >0 ); -/* -* It's possible for mm_access to take a reference on mm_users to -* access the remote mm from another thread, but it's not allowed -* to set mm_cpumask, so mm_users may be > 1 here. -*/ -WARN_ON (current->mm != mm); -atomic_set (&mm->context.active_cpus,1 ); -cpumask_clear (mm_cpumask (mm)); -cpumask_set_cpu (smp_processor_id (),mm_cpumask (mm)); -}#else /* CONFIG_PPC_BOOK3S_64 */ static inline int mm_is_thread_local (struct mm_struct *mm) {
arch/powerpc/mm/book3s64/radix_tlb.c +16 -7
@@ -644,19 +644,29 @@ static void do_exit_flush_lazy_tlb(void *arg)struct mm_struct *mm = arg;unsigned long pid = mm->context.id; +/* +* A kthread could have done a mmget_not_zero() after the flushing CPU +* checked mm_is_singlethreaded, and be in the process of +* kthread_use_mm when interrupted here. In that case, current->mm will +* be set to mm, because kthread_use_mm() setting ->mm and switching to +* the mm is done with interrupts off. +*/ if (current->mm == mm) -return ;/* Local CPU */ + goto out_flush;if (current->active_mm == mm) { -/* -* Must be a kernel thread because sender is single-threaded. -*/ -BUG_ON (current->mm); +WARN_ON_ONCE (current->mm !=NULL ); +/* Is a kernel thread and is using mm as the lazy tlb */ mmgrab (&init_mm); -switch_mm (mm, &init_mm, current); current->active_mm = &init_mm; +switch_mm_irqs_off (mm, &init_mm, current);mmdrop (mm); } + +atomic_dec (&mm->context.active_cpus); +cpumask_clear_cpu (smp_processor_id (),mm_cpumask (mm)); + +out_flush:_tlbiel_pid (pid,RIC_FLUSH_ALL ); }
@@ -671,7 +681,6 @@ static void exit_flush_lazy_tlbs(struct mm_struct *mm)*/ smp_call_function_many (mm_cpumask (mm), do_exit_flush_lazy_tlb, (void *)mm,1 ); -mm_reset_thread_local (mm); }void radix__flush_tlb_mm (struct mm_struct *mm)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 371/633 RDMA/cma: Combine cma_ndev_work with cma_work
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 7e85bcda8bfe883f4244672ed79f81b7762a1a7e ]
These are the same thing, except that cma_ndev_work doesn't have a state transition. Signal no state transition by setting old_state and new_state == 0.
In all cases the handler function should not be called once rdma_destroy_id() has progressed passed setting the state.
--- drivers/infiniband/core/cma.c | 38 +++++++---------------------------- 1 file changed, 7 insertions(+), 31 deletions(-)
drivers/infiniband/core/cma.c +7 -31
@@ -363,12 +363,6 @@ struct cma_work {struct rdma_cm_event event; }; -struct cma_ndev_work { -struct work_struct work; -struct rdma_id_private *id; -struct rdma_cm_event event; -}; -struct iboe_mcast_work {struct work_struct work;struct rdma_id_private *id;
@@ -2646,32 +2640,14 @@ static void cma_work_handler(struct work_struct *_work)struct rdma_id_private *id_priv = work->id;mutex_lock (&id_priv->handler_mutex); -if (!cma_comp_exch (id_priv, work->old_state, work->new_state)) +if (READ_ONCE (id_priv->state) ==RDMA_CM_DESTROYING || +READ_ONCE (id_priv->state) ==RDMA_CM_DEVICE_REMOVAL ) goto out_unlock; - -if (cma_cm_event_handler (id_priv, &work->event)) { -cma_id_put (id_priv); -destroy_id_handler_unlock (id_priv); - goto out_free; +if (work->old_state !=0 || work->new_state !=0 ) { +if (!cma_comp_exch (id_priv, work->old_state, work->new_state)) + goto out_unlock; } -out_unlock: -mutex_unlock (&id_priv->handler_mutex); -cma_id_put (id_priv); -out_free: -kfree (work); -} - -static void cma_ndev_work_handler (struct work_struct *_work) -{ - struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); -struct rdma_id_private *id_priv = work->id; - -mutex_lock (&id_priv->handler_mutex); -if (id_priv->state ==RDMA_CM_DESTROYING || - id_priv->state ==RDMA_CM_DEVICE_REMOVAL ) - goto out_unlock; -if (cma_cm_event_handler (id_priv, &work->event)) {cma_id_put (id_priv);destroy_id_handler_unlock (id_priv);
@@ -4652,7 +4628,7 @@ EXPORT_SYMBOL(rdma_leave_multicast);static int cma_netdev_change (struct net_device *ndev,struct rdma_id_private *id_priv) {struct rdma_dev_addr *dev_addr; -struct cma_ndev_work *work; +struct cma_work *work; dev_addr = &id_priv->id.route.addr.dev_addr;
@@ -4665,7 +4641,7 @@ static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *idif (!work)return -ENOMEM ; -INIT_WORK (&work->work, cma_ndev_work_handler); +INIT_WORK (&work->work, cma_work_handler); work->id = id_priv; work->event.event =RDMA_CM_EVENT_ADDR_CHANGE ;cma_id_get (id_priv);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 372/633 RDMA/cma: Remove dead code for kernel rdmacm multicast
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 1bb5091def706732c749df9aae45fbca003696f2 ]
There is no kernel user of RDMA CM multicast so this code managing the multicast subscription of the kernel-only internal QP is dead. Remove it.
This makes the bug fixes in the next patches much simpler.
--- drivers/infiniband/core/cma.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-)
drivers/infiniband/core/cma.c +4 -15
@@ -4289,16 +4289,6 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)else pr_debug_ratelimited ("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n" , status); -mutex_lock (&id_priv->qp_mutex); -if (!status && id_priv->id.qp) { - status =ib_attach_mcast (id_priv->id.qp, &multicast->rec.mgid, -be16_to_cpu (multicast->rec.mlid)); -if (status) -pr_debug_ratelimited ("RDMA CM: MULTICAST_ERROR: failed to attach QP. status %d\n" , - status); - } -mutex_unlock (&id_priv->qp_mutex); - event.status = status; event.param.ud.private_data = mc->context;if (!status) {
@@ -4551,6 +4541,10 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,struct cma_multicast *mc;int ret; +/* Not supported for kernel QPs */ +if (WARN_ON (id->qp)) +return -EINVAL ; +if (!id->device)return -EINVAL ;
@@ -4605,11 +4599,6 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)list_del (&mc->list);spin_unlock_irq (&id_priv->lock); -if (id->qp) -ib_detach_mcast (id->qp, - &mc->multicast.ib->rec.mgid, -be16_to_cpu (mc->multicast.ib->rec.mlid)); -BUG_ON (id_priv->cma_dev->device != id->device);if (rdma_cap_ib_mcast (id->device, id->port_num)) {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 373/633 RDMA/cma: Consolidate the destruction of a cma_multicast in one place
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 3788d2997bc0150ea911a964d5b5a2e11808a936 ]
Two places were open coding this sequence, and also pull in cma_leave_roce_mc_group() which was called only once.
--- drivers/infiniband/core/cma.c | 63 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 32 deletions(-)
drivers/infiniband/core/cma.c +31 -32
@@ -1777,19 +1777,30 @@ static void cma_release_port(struct rdma_id_private *id_priv)mutex_unlock (&lock); } -static void cma_leave_roce_mc_group (struct rdma_id_private *id_priv, -struct cma_multicast *mc) +static void destroy_mc (struct rdma_id_private *id_priv, +struct cma_multicast *mc) { -struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; -struct net_device *ndev =NULL ; +if (rdma_cap_ib_mcast (id_priv->id.device, id_priv->id.port_num)) { +ib_sa_free_multicast (mc->multicast.ib); +kfree (mc); +return ; + } -if (dev_addr->bound_dev_if) - ndev =dev_get_by_index (dev_addr->net, dev_addr->bound_dev_if); -if (ndev) { -cma_igmp_send (ndev, &mc->multicast.ib->rec.mgid, false); -dev_put (ndev); +if (rdma_protocol_roce (id_priv->id.device, + id_priv->id.port_num)) { +struct rdma_dev_addr *dev_addr = + &id_priv->id.route.addr.dev_addr; +struct net_device *ndev =NULL ; + +if (dev_addr->bound_dev_if) + ndev =dev_get_by_index (dev_addr->net, + dev_addr->bound_dev_if); +if (ndev) { +cma_igmp_send (ndev, &mc->multicast.ib->rec.mgid, false); +dev_put (ndev); + } +kref_put (&mc->mcref, release_mc); } -kref_put (&mc->mcref, release_mc); }static void cma_leave_mc_groups (struct rdma_id_private *id_priv)
@@ -1797,16 +1808,10 @@ static void cma_leave_mc_groups(struct rdma_id_private *id_priv)struct cma_multicast *mc;while (!list_empty (&id_priv->mc_list)) { - mc =container_of (id_priv->mc_list.next, - struct cma_multicast, list); + mc = list_first_entry(&id_priv->mc_list, struct cma_multicast, + list);list_del (&mc->list); -if (rdma_cap_ib_mcast (id_priv->cma_dev->device, - id_priv->id.port_num)) { -ib_sa_free_multicast (mc->multicast.ib); -kfree (mc); - }else { -cma_leave_roce_mc_group (id_priv, mc); - } +destroy_mc (id_priv, mc); } }
@@ -4595,20 +4600,14 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) id_priv = container_of(id, struct rdma_id_private, id);spin_lock_irq (&id_priv->lock);list_for_each_entry (mc, &id_priv->mc_list, list) { -if (!memcmp (&mc->addr, addr,rdma_addr_size (addr))) { -list_del (&mc->list); -spin_unlock_irq (&id_priv->lock); - -BUG_ON (id_priv->cma_dev->device != id->device); +if (memcmp (&mc->addr, addr,rdma_addr_size (addr)) !=0 ) +continue ; +list_del (&mc->list); +spin_unlock_irq (&id_priv->lock); -if (rdma_cap_ib_mcast (id->device, id->port_num)) { -ib_sa_free_multicast (mc->multicast.ib); -kfree (mc); - }else if (rdma_protocol_roce (id->device, id->port_num)) { -cma_leave_roce_mc_group (id_priv, mc); - } -return ; - } +WARN_ON (id_priv->cma_dev->device != id->device); +destroy_mc (id_priv, mc); +return ; }spin_unlock_irq (&id_priv->lock); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 374/633 RDMA/cma: Fix use after free race in roce multicast join
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit b5de0c60cc30c2a3513c7188c73f3f29acc29234 ]
The roce path triggers a work queue that continues to touch the id_priv but doesn't hold any reference on it. Futher, unlike in the IB case, the work queue is not fenced during rdma_destroy_id().
This can trigger a use after free if a destroy is triggered in the incredibly narrow window after the queue_work and the work starting and obtaining the handler_mutex.
The only purpose of this work queue is to run the ULP event callback from the standard context, so switch the design to use the existing cma_work_handler() scheme. This simplifies quite a lot of the flow:
- Use the cma_work_handler() callback to launch the work for roce. This requires generating the event synchronously inside the rdma_join_multicast(), which in turn means the dummy struct ib_sa_multicast can become a simple stack variable.
- cm_work_handler() used the id_priv kref, so we can entirely eliminate the kref inside struct cma_multicast. Since the cma_multicast never leaks into an unprotected work queue the kfree can be done at the same time as for IB.
- Eliminating the general multicast.ib requires using cma_set_mgid() in a few places to recompute the mgid.
--- drivers/infiniband/core/cma.c | 196 +++++++++++++++------------------- 1 file changed, 88 insertions(+), 108 deletions(-)
drivers/infiniband/core/cma.c +88 -108
@@ -68,6 +68,9 @@ static const char * const cma_events[] = { [RDMA_CM_EVENT_TIMEWAIT_EXIT] = "timewait exit", }; +static void cma_set_mgid (struct rdma_id_private *id_priv,struct sockaddr *addr, +union ib_gid *mgid); + const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event) {size_t index = event;
@@ -345,13 +348,10 @@ struct ib_device *cma_get_ib_dev(struct cma_device *cma_dev)struct cma_multicast {struct rdma_id_private *id_priv; -union { -struct ib_sa_multicast *ib; - } multicast; +struct ib_sa_multicast *sa_mc;struct list_head list;void *context;struct sockaddr_storage addr; -struct kref mcref;u8 join_state; };
@@ -363,12 +363,6 @@ struct cma_work {struct rdma_cm_event event; }; -struct iboe_mcast_work { -struct work_struct work; -struct rdma_id_private *id; -struct cma_multicast *mc; -}; -union cma_ip_addr {struct in6_addr ip6;struct {
@@ -477,14 +471,6 @@ static void cma_attach_to_dev(struct rdma_id_private *id_priv, rdma_start_port(cma_dev->device)]; } -static inline void release_mc (struct kref *kref) -{ - struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref); - -kfree (mc->multicast.ib); -kfree (mc); -} -static void cma_release_dev (struct rdma_id_private *id_priv) {mutex_lock (&lock);
@@ -1780,14 +1766,10 @@ static void cma_release_port(struct rdma_id_private *id_priv)static void destroy_mc (struct rdma_id_private *id_priv,struct cma_multicast *mc) { -if (rdma_cap_ib_mcast (id_priv->id.device, id_priv->id.port_num)) { -ib_sa_free_multicast (mc->multicast.ib); -kfree (mc); -return ; - } +if (rdma_cap_ib_mcast (id_priv->id.device, id_priv->id.port_num)) +ib_sa_free_multicast (mc->sa_mc); -if (rdma_protocol_roce (id_priv->id.device, - id_priv->id.port_num)) { +if (rdma_protocol_roce (id_priv->id.device, id_priv->id.port_num)) {struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;struct net_device *ndev =NULL ;
@@ -1796,11 +1778,15 @@ static void destroy_mc(struct rdma_id_private *id_priv, ndev =dev_get_by_index (dev_addr->net, dev_addr->bound_dev_if);if (ndev) { -cma_igmp_send (ndev, &mc->multicast.ib->rec.mgid, false); +union ib_gid mgid; + +cma_set_mgid (id_priv, (struct sockaddr *)&mc->addr, + &mgid); +cma_igmp_send (ndev, &mgid, false);dev_put (ndev); } -kref_put (&mc->mcref, release_mc); } +kfree (mc); }static void cma_leave_mc_groups (struct rdma_id_private *id_priv)
@@ -2663,6 +2649,8 @@ static void cma_work_handler(struct work_struct *_work)mutex_unlock (&id_priv->handler_mutex);cma_id_put (id_priv); out_free: +if (work->event.event ==RDMA_CM_EVENT_MULTICAST_JOIN ) +rdma_destroy_ah_attr (&work->event.param.ud.ah_attr);kfree (work); }
@@ -4276,53 +4264,66 @@ int rdma_disconnect(struct rdma_cm_id *id) }EXPORT_SYMBOL (rdma_disconnect); +static void cma_make_mc_event (int status,struct rdma_id_private *id_priv, +struct ib_sa_multicast *multicast, +struct rdma_cm_event *event, +struct cma_multicast *mc) +{ +struct rdma_dev_addr *dev_addr; +enum ib_gid_type gid_type; +struct net_device *ndev; + +if (!status) + status =cma_set_qkey (id_priv,be32_to_cpu (multicast->rec.qkey)); +else +pr_debug_ratelimited ("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n" , + status); + + event->status = status; + event->param.ud.private_data = mc->context; +if (status) { + event->event =RDMA_CM_EVENT_MULTICAST_ERROR ; +return ; + } + + dev_addr = &id_priv->id.route.addr.dev_addr; + ndev =dev_get_by_index (dev_addr->net, dev_addr->bound_dev_if); + gid_type = + id_priv->cma_dev + ->default_gid_type[id_priv->id.port_num - +rdma_start_port ( + id_priv->cma_dev->device)]; + + event->event =RDMA_CM_EVENT_MULTICAST_JOIN ; +if (ib_init_ah_from_mcmember (id_priv->id.device, id_priv->id.port_num, + &multicast->rec, ndev, gid_type, + &event->param.ud.ah_attr)) { + event->event =RDMA_CM_EVENT_MULTICAST_ERROR ; + goto out; + } + + event->param.ud.qp_num =0xFFFFFF ; + event->param.ud.qkey =be32_to_cpu (multicast->rec.qkey); + +out: +if (ndev) +dev_put (ndev); +} +static int cma_ib_mc_handler (int status,struct ib_sa_multicast *multicast) { -struct rdma_id_private *id_priv;struct cma_multicast *mc = multicast->context; +struct rdma_id_private *id_priv = mc->id_priv;struct rdma_cm_event event = {};int ret =0 ; - id_priv = mc->id_priv;mutex_lock (&id_priv->handler_mutex);if (id_priv->state !=RDMA_CM_ADDR_BOUND && id_priv->state !=RDMA_CM_ADDR_RESOLVED ) goto out; -if (!status) - status =cma_set_qkey (id_priv,be32_to_cpu (multicast->rec.qkey)); -else -pr_debug_ratelimited ("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n" , - status); - event.status = status; - event.param.ud.private_data = mc->context; -if (!status) { -struct rdma_dev_addr *dev_addr = - &id_priv->id.route.addr.dev_addr; -struct net_device *ndev = -dev_get_by_index (dev_addr->net, dev_addr->bound_dev_if); -enum ib_gid_type gid_type = - id_priv->cma_dev->default_gid_type[id_priv->id.port_num - -rdma_start_port (id_priv->cma_dev->device)]; - - event.event =RDMA_CM_EVENT_MULTICAST_JOIN ; - ret =ib_init_ah_from_mcmember (id_priv->id.device, - id_priv->id.port_num, - &multicast->rec, - ndev, gid_type, - &event.param.ud.ah_attr); -if (ret) - event.event =RDMA_CM_EVENT_MULTICAST_ERROR ; - - event.param.ud.qp_num =0xFFFFFF ; - event.param.ud.qkey =be32_to_cpu (multicast->rec.qkey); -if (ndev) -dev_put (ndev); - }else - event.event =RDMA_CM_EVENT_MULTICAST_ERROR ; - +cma_make_mc_event (status, id_priv, multicast, &event, mc); ret =cma_cm_event_handler (id_priv, &event); -rdma_destroy_ah_attr (&event.param.ud.ah_attr);if (ret) {destroy_id_handler_unlock (id_priv);
@@ -4412,23 +4413,10 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,IB_SA_MCMEMBER_REC_MTU |IB_SA_MCMEMBER_REC_HOP_LIMIT ; - mc->multicast.ib =ib_sa_join_multicast (&sa_client, id_priv->id.device, - id_priv->id.port_num, &rec, - comp_mask,GFP_KERNEL , - cma_ib_mc_handler, mc); -return PTR_ERR_OR_ZERO (mc->multicast.ib); -} - -static void iboe_mcast_work_handler (struct work_struct *work) -{ - struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work); -struct cma_multicast *mc = mw->mc; -struct ib_sa_multicast *m = mc->multicast.ib; - - mc->multicast.ib->context = mc; -cma_ib_mc_handler (0 , m); -kref_put (&mc->mcref, release_mc); -kfree (mw); + mc->sa_mc =ib_sa_join_multicast (&sa_client, id_priv->id.device, + id_priv->id.port_num, &rec, comp_mask, +GFP_KERNEL , cma_ib_mc_handler, mc); +return PTR_ERR_OR_ZERO (mc->sa_mc); } static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
@@ -4463,52 +4451,47 @@ static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,static int cma_iboe_join_multicast (struct rdma_id_private *id_priv,struct cma_multicast *mc) { -struct iboe_mcast_work *work; +struct cma_work *work;struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;int err =0 ;struct sockaddr *addr = (struct sockaddr *)&mc->addr;struct net_device *ndev =NULL ; +struct ib_sa_multicast ib;enum ib_gid_type gid_type;bool send_only; send_only = mc->join_state ==BIT (SENDONLY_FULLMEMBER_JOIN ); -if (cma_zero_addr ((struct sockaddr *)&mc->addr)) +if (cma_zero_addr (addr))return -EINVAL ; work =kzalloc (sizeof *work,GFP_KERNEL );if (!work)return -ENOMEM ; - mc->multicast.ib =kzalloc (sizeof (struct ib_sa_multicast ),GFP_KERNEL ); -if (!mc->multicast.ib) { - err = -ENOMEM ; - goto out1; - } - gid_type = id_priv->cma_dev->default_gid_type[id_priv->id.port_num -rdma_start_port (id_priv->cma_dev->device)]; -cma_iboe_set_mgid (addr, &mc->multicast.ib->rec.mgid, gid_type); +cma_iboe_set_mgid (addr, &ib.rec.mgid, gid_type); - mc->multicast.ib->rec.pkey =cpu_to_be16 (0xffff ); + ib.rec.pkey =cpu_to_be16 (0xffff );if (id_priv->id.ps ==RDMA_PS_UDP ) - mc->multicast.ib->rec.qkey =cpu_to_be32 (RDMA_UDP_QKEY ); + ib.rec.qkey =cpu_to_be32 (RDMA_UDP_QKEY );if (dev_addr->bound_dev_if) ndev =dev_get_by_index (dev_addr->net, dev_addr->bound_dev_if);if (!ndev) { err = -ENODEV ; - goto out2; + goto err_free; } - mc->multicast.ib->rec.rate =iboe_get_rate (ndev); - mc->multicast.ib->rec.hop_limit =1 ; - mc->multicast.ib->rec.mtu =iboe_get_mtu (ndev->mtu); + ib.rec.rate =iboe_get_rate (ndev); + ib.rec.hop_limit =1 ; + ib.rec.mtu =iboe_get_mtu (ndev->mtu);if (addr->sa_family ==AF_INET ) {if (gid_type ==IB_GID_TYPE_ROCE_UDP_ENCAP ) { - mc->multicast.ib->rec.hop_limit =IPV6_DEFAULT_HOPLIMIT ; + ib.rec.hop_limit =IPV6_DEFAULT_HOPLIMIT ;if (!send_only) { - err =cma_igmp_send (ndev, &mc->multicast.ib->rec.mgid, + err =cma_igmp_send (ndev, &ib.rec.mgid, true); } }
@@ -4517,24 +4500,22 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, err = -ENOTSUPP ; }dev_put (ndev); -if (err || !mc->multicast.ib->rec.mtu) { +if (err || !ib.rec.mtu) {if (!err) err = -EINVAL ; - goto out2; + goto err_free; }rdma_ip2gid ((struct sockaddr *)&id_priv->id.route.addr.src_addr, - &mc->multicast.ib->rec.port_gid); + &ib.rec.port_gid); work->id = id_priv; - work->mc = mc; -INIT_WORK (&work->work, iboe_mcast_work_handler); -kref_get (&mc->mcref); +INIT_WORK (&work->work, cma_work_handler); +cma_make_mc_event (0 , id_priv, &ib, &work->event, mc); +/* Balances with cma_id_put() in cma_work_handler */ +cma_id_get (id_priv);queue_work (cma_wq, &work->work); -return 0 ; -out2: -kfree (mc->multicast.ib); -out1: +err_free:kfree (work);return err; }
@@ -4558,7 +4539,7 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))return -EINVAL ; - mc =kmalloc (sizeof *mc,GFP_KERNEL ); + mc =kzalloc (sizeof (*mc),GFP_KERNEL );if (!mc)return -ENOMEM ;
@@ -4568,7 +4549,6 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, mc->join_state = join_state;if (rdma_protocol_roce (id->device, id->port_num)) { -kref_init (&mc->mcref); ret =cma_iboe_join_multicast (id_priv, mc);if (ret) goto out_err;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 375/633 perf intel-pt: Fix "context_switch event has no tid" error
In reply to Greg Kroah-HartmanFrom: Adrian Hunter <[email protected]>
[ Upstream commit 7d537a8d2e76bc4fc71e34545ceaa463ac2cd928 ]
A context_switch event can have no tid because pids can be detached from a task while the task is still running (in do_exit()). Note this won't happen with per-task contexts because then tracing stops at perf_event_exit_task()
If a task with no tid gets preempted, or a dying task gets preempted and its parent releases it, when it subsequently gets switched back in, Intel PT will not be able to determine what task is running and prints an error "context_switch event has no tid". However, it is not really an error because the task is in kernel space and the decoder can continue to decode successfully. Fix by changing the error to be only a logged message, and make allowance for tid == -1.
Example:
Using 5.9-rc4 with Preemptible Kernel (Low-Latency Desktop) e.g.
$ uname -r 5.9.0-rc4 $ grep PREEMPT .config # CONFIG_PREEMPT_NONE is not set # CONFIG_PREEMPT_VOLUNTARY is not set CONFIG_PREEMPT=y CONFIG_PREEMPT_COUNT=y CONFIG_PREEMPTION=y CONFIG_PREEMPT_RCU=y CONFIG_PREEMPT_NOTIFIERS=y CONFIG_DRM_I915_PREEMPT_TIMEOUT=640 CONFIG_DEBUG_PREEMPT=y # CONFIG_PREEMPT_TRACER is not set # CONFIG_PREEMPTIRQ_DELAY_TEST is not set
Before:
$ cat forkit.c
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t child;
int status = 0; child = fork();
if (child == 0)
return 123;
wait(&status);
return 0;}
$ gcc -o forkit forkit.c $ sudo ~/bin/perf record --kcore -a -m,64M -e intel_pt/cyc/k & [1] 11016 $ taskset 2 ./forkit $ sudo pkill perf $ [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 17.262 MB perf.data ]
[1]+ Terminated sudo ~/bin/perf record --kcore -a -m,64M -e intel_pt/cyc/k
$ sudo ~/bin/perf script --show-task-events --show-switch-events --itrace=iqqe-o -C 1 --ns | grep -C 2 forkit
context_switch event has no tid
taskset 11019 [001] 66663.270045029: 1 instructions:k: ffffffffb1d9f844 strnlen_user+0xb4 ([kernel.kallsyms])
taskset 11019 [001] 66663.270201816: 1 instructions:k: ffffffffb1a83121 unmap_page_range+0x561 ([kernel.kallsyms])
forkit 11019 [001] 66663.270327553: PERF_RECORD_COMM exec: forkit:11019/11019
forkit 11019 [001] 66663.270420028: 1 instructions:k: ffffffffb1db9537 __clear_user+0x27 ([kernel.kallsyms])
forkit 11019 [001] 66663.270648704: 1 instructions:k: ffffffffb18829e6 do_user_addr_fault+0xf6 ([kernel.kallsyms])
forkit 11019 [001] 66663.270833163: 1 instructions:k: ffffffffb230a825 irqentry_exit_to_user_mode+0x15 ([kernel.kallsyms])
forkit 11019 [001] 66663.271092359: 1 instructions:k: ffffffffb1aea3d9 lock_page_memcg+0x9 ([kernel.kallsyms])
forkit 11019 [001] 66663.271207092: PERF_RECORD_FORK(11020:11020):(11019:11019)
forkit 11019 [001] 66663.271234775: PERF_RECORD_SWITCH_CPU_WIDE OUT next pid/tid: 11020/11020
forkit 11020 [001] 66663.271238407: PERF_RECORD_SWITCH_CPU_WIDE IN prev pid/tid: 11019/11019
forkit 11020 [001] 66663.271312066: 1 instructions:k: ffffffffb1a88140 handle_mm_fault+0x10 ([kernel.kallsyms])
forkit 11020 [001] 66663.271476225: PERF_RECORD_EXIT(11020:11020):(11019:11019)
forkit 11020 [001] 66663.271497488: PERF_RECORD_SWITCH_CPU_WIDE OUT preempt next pid/tid: 11019/11019
forkit 11019 [001] 66663.271500523: PERF_RECORD_SWITCH_CPU_WIDE IN prev pid/tid: 11020/11020
forkit 11019 [001] 66663.271517241: 1 instructions:k: ffffffffb24012cd error_entry+0x6d ([kernel.kallsyms])
forkit 11019 [001] 66663.271664080: PERF_RECORD_EXIT(11019:11019):(1386:1386)After:
$ sudo ~/bin/perf script --show-task-events --show-switch-events --itrace=iqqe-o -C 1 --ns | grep -C 2 forkit
taskset 11019 [001] 66663.270045029: 1 instructions:k: ffffffffb1d9f844 strnlen_user+0xb4 ([kernel.kallsyms])
taskset 11019 [001] 66663.270201816: 1 instructions:k: ffffffffb1a83121 unmap_page_range+0x561 ([kernel.kallsyms])
forkit 11019 [001] 66663.270327553: PERF_RECORD_COMM exec: forkit:11019/11019
forkit 11019 [001] 66663.270420028: 1 instructions:k: ffffffffb1db9537 __clear_user+0x27 ([kernel.kallsyms])
forkit 11019 [001] 66663.270648704: 1 instructions:k: ffffffffb18829e6 do_user_addr_fault+0xf6 ([kernel.kallsyms])
forkit 11019 [001] 66663.270833163: 1 instructions:k: ffffffffb230a825 irqentry_exit_to_user_mode+0x15 ([kernel.kallsyms])
forkit 11019 [001] 66663.271092359: 1 instructions:k: ffffffffb1aea3d9 lock_page_memcg+0x9 ([kernel.kallsyms])
forkit 11019 [001] 66663.271207092: PERF_RECORD_FORK(11020:11020):(11019:11019)
forkit 11019 [001] 66663.271234775: PERF_RECORD_SWITCH_CPU_WIDE OUT next pid/tid: 11020/11020
forkit 11020 [001] 66663.271238407: PERF_RECORD_SWITCH_CPU_WIDE IN prev pid/tid: 11019/11019
forkit 11020 [001] 66663.271312066: 1 instructions:k: ffffffffb1a88140 handle_mm_fault+0x10 ([kernel.kallsyms])
forkit 11020 [001] 66663.271476225: PERF_RECORD_EXIT(11020:11020):(11019:11019)
forkit 11020 [001] 66663.271497488: PERF_RECORD_SWITCH_CPU_WIDE OUT preempt next pid/tid: 11019/11019
forkit 11019 [001] 66663.271500523: PERF_RECORD_SWITCH_CPU_WIDE IN prev pid/tid: 11020/11020
forkit 11019 [001] 66663.271517241: 1 instructions:k: ffffffffb24012cd error_entry+0x6d ([kernel.kallsyms])
forkit 11019 [001] 66663.271664080: PERF_RECORD_EXIT(11019:11019):(1386:1386)
forkit 11019 [001] 66663.271688752: PERF_RECORD_SWITCH_CPU_WIDE OUT next pid/tid: -1/-1
:-1 -1 [001] 66663.271692086: PERF_RECORD_SWITCH_CPU_WIDE IN prev pid/tid: 11019/11019
:-1 -1 [001] 66663.271707466: 1 instructions:k: ffffffffb18eb096 update_load_avg+0x306 ([kernel.kallsyms])--- tools/perf/util/intel-pt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/perf/util/intel-pt.c +4 -4
@@ -1071,6 +1071,8 @@ static void intel_pt_set_pid_tid_cpu(struct intel_pt *pt,if (queue->tid ==-1 || pt->have_sched_switch) { ptq->tid =machine__get_current_tid (pt->machine, ptq->cpu); +if (ptq->tid ==-1 ) + ptq->pid =-1 ;thread__zput (ptq->thread); }
@@ -2561,10 +2563,8 @@ static int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event, tid = sample->tid; } -if (tid ==-1 ) { -pr_err ("context_switch event has no tid\n" ); -return -EINVAL ; - } +if (tid ==-1 ) +intel_pt_log ("context_switch event has no tid\n" ); intel_pt_log("context_switch: cpu %d pid %d tid %d time %"PRIu64" tsc %#"PRIx64"\n", cpu, pid, tid, sample->time, perf_time_to_tsc(sample->time,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 376/633 RDMA/qedr: Fix resource leak in qedr_create_qp
In reply to Greg Kroah-HartmanFrom: Keita Suzuki <[email protected]>
[ Upstream commit 3e45410fe3c202ffb619f301beff0644f717e132 ]
When xa_insert() fails, the acquired resource in qedr_create_qp should also be freed. However, current implementation does not handle the error.
Fix this by adding a new goto label that calls qedr_free_qp_resources.
--- drivers/infiniband/hw/qedr/verbs.c | 52 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 25 deletions(-)
drivers/infiniband/hw/qedr/verbs.c +27 -25
@@ -2113,6 +2113,28 @@ static int qedr_create_kernel_qp(struct qedr_dev *dev,return rc; } +static int qedr_free_qp_resources (struct qedr_dev *dev,struct qedr_qp *qp, +struct ib_udata *udata) +{ +struct qedr_ucontext *ctx = + rdma_udata_to_drv_context(udata, struct qedr_ucontext, + ibucontext); +int rc; + +if (qp->qp_type !=IB_QPT_GSI ) { + rc = dev->ops->rdma_destroy_qp (dev->rdma_ctx, qp->qed_qp); +if (rc) +return rc; + } + +if (qp->create_type ==QEDR_QP_CREATE_USER ) +qedr_cleanup_user (dev, ctx, qp); +else +qedr_cleanup_kernel (dev, qp); + +return 0 ; +} +struct ib_qp *qedr_create_qp (struct ib_pd *ibpd,struct ib_qp_init_attr *attrs,struct ib_udata *udata)
@@ -2159,19 +2181,21 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd, rc =qedr_create_kernel_qp (dev, qp, ibpd, attrs);if (rc) - goto err; + goto out_free_qp; qp->ibqp.qp_num = qp->qp_id;if (rdma_protocol_iwarp (&dev->ibdev,1 )) { rc =xa_insert (&dev->qps, qp->qp_id, qp,GFP_KERNEL );if (rc) - goto err; + goto out_free_qp_resources; }return &qp->ibqp; -err: +out_free_qp_resources: +qedr_free_qp_resources (dev, qp, udata); +out_free_qp:kfree (qp);return ERR_PTR (-EFAULT );
@@ -2672,28 +2696,6 @@ int qedr_query_qp(struct ib_qp *ibqp,return rc; } -static int qedr_free_qp_resources (struct qedr_dev *dev,struct qedr_qp *qp, -struct ib_udata *udata) -{ -struct qedr_ucontext *ctx = - rdma_udata_to_drv_context(udata, struct qedr_ucontext, - ibucontext); -int rc; - -if (qp->qp_type !=IB_QPT_GSI ) { - rc = dev->ops->rdma_destroy_qp (dev->rdma_ctx, qp->qed_qp); -if (rc) -return rc; - } - -if (qp->create_type ==QEDR_QP_CREATE_USER ) -qedr_cleanup_user (dev, ctx, qp); -else -qedr_cleanup_kernel (dev, qp); - -return 0 ; -} -int qedr_destroy_qp (struct ib_qp *ibqp,struct ib_udata *udata) {struct qedr_qp *qp =get_qedr_qp (ibqp);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 377/633 RDMA/hns: Set the unsupported wr opcode
In reply to Greg Kroah-HartmanFrom: Lijun Ou <[email protected]>
[ Upstream commit 22d3e1ed2cc837af87f76c3c8a4ccf4455e225c5 ]
hip06 does not support IB_WR_LOCAL_INV, so the ps_opcode should be set to an invalid value instead of being left uninitialized.
--- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 1 - 1 file changed, 1 deletion(-)
drivers/infiniband/hw/hns/hns_roce_hw_v1.c +0 -1
@@ -271,7 +271,6 @@ static int hns_roce_v1_post_send(struct ib_qp *ibqp, ps_opcode =HNS_ROCE_WQE_OPCODE_SEND ;break ;case IB_WR_LOCAL_INV : -break ;case IB_WR_ATOMIC_CMP_AND_SWP :case IB_WR_ATOMIC_FETCH_AND_ADD :case IB_WR_LSO :
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 378/633 RDMA/mlx5: Use set_mkc_access_pd_addr_fields() in reg_create()
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 1c97ca3da0d12e0156a177f48ed3184c3f202002 ]
reg_create() open codes this helper, use the shared code.
--- drivers/infiniband/hw/mlx5/mr.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-)
drivers/infiniband/hw/mlx5/mr.c +1 -14
@@ -1190,29 +1190,16 @@ static struct mlx5_ib_mr *reg_create(struct ib_mr *ibmr, struct ib_pd *pd,MLX5_SET (create_mkey_in, in, pg_access, !!(pg_cap)); mkc =MLX5_ADDR_OF (create_mkey_in, in, memory_key_mkey_entry); +set_mkc_access_pd_addr_fields (mkc, access_flags, virt_addr, pd);MLX5_SET (mkc, mkc, free, !populate);MLX5_SET (mkc, mkc, access_mode_1_0,MLX5_MKC_ACCESS_MODE_MTT ); -if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write)) -MLX5_SET (mkc, mkc, relaxed_ordering_write, - !!(access_flags &IB_ACCESS_RELAXED_ORDERING )); -if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read)) -MLX5_SET (mkc, mkc, relaxed_ordering_read, - !!(access_flags &IB_ACCESS_RELAXED_ORDERING )); -MLX5_SET (mkc, mkc, a, !!(access_flags &IB_ACCESS_REMOTE_ATOMIC )); -MLX5_SET (mkc, mkc, rw, !!(access_flags &IB_ACCESS_REMOTE_WRITE )); -MLX5_SET (mkc, mkc, rr, !!(access_flags &IB_ACCESS_REMOTE_READ )); -MLX5_SET (mkc, mkc, lw, !!(access_flags &IB_ACCESS_LOCAL_WRITE )); -MLX5_SET (mkc, mkc, lr,1 );MLX5_SET (mkc, mkc, umr_en,1 ); -MLX5_SET64 (mkc, mkc, start_addr, virt_addr);MLX5_SET64 (mkc, mkc, len, length); -MLX5_SET (mkc, mkc, pd,to_mpd (pd)->pdn);MLX5_SET (mkc, mkc, bsf_octword_size,0 );MLX5_SET (mkc, mkc, translations_octword_size,get_octo_len (virt_addr, length, page_shift));MLX5_SET (mkc, mkc, log_page_size, page_shift); -MLX5_SET (mkc, mkc, qpn,0xffffff );if (populate) {MLX5_SET (create_mkey_in, in, translations_octword_actual_size,get_octo_len (virt_addr, length, page_shift));
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 379/633 RDMA/mlx5: Make mkeys always owned by the kernels PD when not enabled
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 5eb29f0d13a66502b91954597270003c90fb66c5 ]
Any mkey that is not enabled and assigned to userspace should have the PD set to a kernel owned PD.
When cache entries are created for the first time the PDN is set to 0, which is probably a kernel PD, but be explicit.
When a MR is registered using the hybrid reg_create with UMR xlt & enable the disabled mkey is pointing at the user PD, keep it pointing at the kernel until a UMR enables it and sets the user PD.
--- drivers/infiniband/hw/mlx5/mr.c | 51 +++++++++++++++++---------------- 1 file changed, 26 insertions(+), 25 deletions(-)
drivers/infiniband/hw/mlx5/mr.c +26 -25
@@ -50,6 +50,29 @@ enum {static void create_mkey_callback (int status,struct mlx5_async_work *context); +static void set_mkc_access_pd_addr_fields (void *mkc,int acc,u64 start_addr, +struct ib_pd *pd) +{ +struct mlx5_ib_dev *dev =to_mdev (pd->device); + +MLX5_SET (mkc, mkc, a, !!(acc &IB_ACCESS_REMOTE_ATOMIC )); +MLX5_SET (mkc, mkc, rw, !!(acc &IB_ACCESS_REMOTE_WRITE )); +MLX5_SET (mkc, mkc, rr, !!(acc &IB_ACCESS_REMOTE_READ )); +MLX5_SET (mkc, mkc, lw, !!(acc &IB_ACCESS_LOCAL_WRITE )); +MLX5_SET (mkc, mkc, lr,1 ); + +if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write)) +MLX5_SET (mkc, mkc, relaxed_ordering_write, + !!(acc &IB_ACCESS_RELAXED_ORDERING )); +if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read)) +MLX5_SET (mkc, mkc, relaxed_ordering_read, + !!(acc &IB_ACCESS_RELAXED_ORDERING )); + +MLX5_SET (mkc, mkc, pd,to_mpd (pd)->pdn); +MLX5_SET (mkc, mkc, qpn,0xffffff ); +MLX5_SET64 (mkc, mkc, start_addr, start_addr); +} +static void assign_mkey_variant (struct mlx5_ib_dev *dev,struct mlx5_core_mkey *mkey,u32 *in)
@@ -152,12 +175,12 @@ static struct mlx5_ib_mr *alloc_cache_mr(struct mlx5_cache_ent *ent, void *mkc) mr->cache_ent = ent; mr->dev = ent->dev; +set_mkc_access_pd_addr_fields (mkc,0 ,0 , ent->dev->umrc.pd);MLX5_SET (mkc, mkc, free,1 );MLX5_SET (mkc, mkc, umr_en,1 );MLX5_SET (mkc, mkc, access_mode_1_0, ent->access_mode &0x3 );MLX5_SET (mkc, mkc, access_mode_4_2, (ent->access_mode >>2 ) &0x7 ); -MLX5_SET (mkc, mkc, qpn,0xffffff );MLX5_SET (mkc, mkc, translations_octword_size, ent->xlt);MLX5_SET (mkc, mkc, log_page_size, ent->page);return mr;
@@ -774,29 +797,6 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)return 0 ; } -static void set_mkc_access_pd_addr_fields (void *mkc,int acc,u64 start_addr, -struct ib_pd *pd) -{ -struct mlx5_ib_dev *dev =to_mdev (pd->device); - -MLX5_SET (mkc, mkc, a, !!(acc &IB_ACCESS_REMOTE_ATOMIC )); -MLX5_SET (mkc, mkc, rw, !!(acc &IB_ACCESS_REMOTE_WRITE )); -MLX5_SET (mkc, mkc, rr, !!(acc &IB_ACCESS_REMOTE_READ )); -MLX5_SET (mkc, mkc, lw, !!(acc &IB_ACCESS_LOCAL_WRITE )); -MLX5_SET (mkc, mkc, lr,1 ); - -if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_write)) -MLX5_SET (mkc, mkc, relaxed_ordering_write, - !!(acc &IB_ACCESS_RELAXED_ORDERING )); -if (MLX5_CAP_GEN (dev->mdev, relaxed_ordering_read)) -MLX5_SET (mkc, mkc, relaxed_ordering_read, - !!(acc &IB_ACCESS_RELAXED_ORDERING )); - -MLX5_SET (mkc, mkc, pd,to_mpd (pd)->pdn); -MLX5_SET (mkc, mkc, qpn,0xffffff ); -MLX5_SET64 (mkc, mkc, start_addr, start_addr); -} -struct ib_mr *mlx5_ib_get_dma_mr (struct ib_pd *pd,int acc) {struct mlx5_ib_dev *dev =to_mdev (pd->device);
@@ -1190,7 +1190,8 @@ static struct mlx5_ib_mr *reg_create(struct ib_mr *ibmr, struct ib_pd *pd,MLX5_SET (create_mkey_in, in, pg_access, !!(pg_cap)); mkc =MLX5_ADDR_OF (create_mkey_in, in, memory_key_mkey_entry); -set_mkc_access_pd_addr_fields (mkc, access_flags, virt_addr, pd); +set_mkc_access_pd_addr_fields (mkc, access_flags, virt_addr, + populate ? pd : dev->umrc.pd);MLX5_SET (mkc, mkc, free, !populate);MLX5_SET (mkc, mkc, access_mode_1_0,MLX5_MKC_ACCESS_MODE_MTT );MLX5_SET (mkc, mkc, umr_en,1 );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 380/633 RDMA/mlx5: Disable IB_DEVICE_MEM_MGT_EXTENSIONS if IB_WR_REG_MR cant work
In reply to Greg Kroah-HartmanFrom: Jason Gunthorpe <[email protected]>
[ Upstream commit 0ec52f0194638e2d284ad55eba5a7aff753de1b9 ]
set_reg_wr() always fails if !umr_modify_entity_size_disabled because mlx5_ib_can_use_umr() always fails. Without set_reg_wr() IB_WR_REG_MR doesn't work and that means the device should not advertise IB_DEVICE_MEM_MGT_EXTENSIONS.
--- drivers/infiniband/hw/mlx5/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/main.c +3 -1
@@ -867,7 +867,9 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,/* We support 'Gappy' memory registration too */ props->device_cap_flags |=IB_DEVICE_SG_GAPS_REG ; } - props->device_cap_flags |=IB_DEVICE_MEM_MGT_EXTENSIONS ; +/* IB_WR_REG_MR always requires changing the entity size with UMR */ +if (!MLX5_CAP_GEN (dev->mdev, umr_modify_entity_size_disabled)) + props->device_cap_flags |=IB_DEVICE_MEM_MGT_EXTENSIONS ;if (MLX5_CAP_GEN (mdev, sho)) { props->device_cap_flags |=IB_DEVICE_INTEGRITY_HANDOVER ;/* At this stage no support for signature handover */
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 381/633 i40iw: Add support to make destroy QP synchronous
In reply to Greg Kroah-HartmanFrom: Sindhu, Devale <[email protected]>
[ Upstream commit f2334964e969762e266a616acf9377f6046470a2 ]
Occasionally ib_write_bw crash is seen due to access of a pd object in i40iw_sc_qp_destroy after it is freed. Destroy qp is not synchronous in i40iw and thus the iwqp object could be referencing a pd object that is freed by ib core as a result of successful return from i40iw_destroy_qp.
Wait in i40iw_destroy_qp till all QP references are released and destroy the QP and its associated resources before returning. Switch to use the refcount API vs atomic API for lifetime management of the qp.
RIP: 0010:i40iw_sc_qp_destroy+0x4b/0x120 [i40iw] [...] RSP: 0018:ffffb4a7042e3ba8 EFLAGS: 00010002 RAX: 0000000000000000 RBX: 0000000000000001 RCX: dead000000000122 RDX: ffffb4a7042e3bac RSI: ffff8b7ef9b1e940 RDI: ffff8b7efbf09080 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000000 R10: 8080808080808080 R11: 0000000000000010 R12: ffff8b7efbf08050 R13: 0000000000000001 R14: ffff8b7f15042928 R15: ffff8b7ef9b1e940 FS: 0000000000000000(0000) GS:ffff8b7f2fa00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000400 CR3: 000000020d60a006 CR4: 00000000001606e0 Call Trace: i40iw_exec_cqp_cmd+0x4d3/0x5c0 [i40iw] ? try_to_wake_up+0x1ea/0x5d0 ? __switch_to_asm+0x40/0x70 i40iw_process_cqp_cmd+0x95/0xa0 [i40iw] i40iw_handle_cqp_op+0x42/0x1a0 [i40iw] ? cm_event_handler+0x13c/0x1f0 [iw_cm] i40iw_rem_ref+0xa0/0xf0 [i40iw] cm_work_handler+0x99c/0xd10 [iw_cm] process_one_work+0x1a1/0x360 worker_thread+0x30/0x380 ? process_one_work+0x360/0x360 kthread+0x10c/0x130 ? kthread_park+0x80/0x80 ret_from_fork+0x35/0x40
--- drivers/infiniband/hw/i40iw/i40iw.h | 9 ++-- drivers/infiniband/hw/i40iw/i40iw_cm.c | 10 ++-- drivers/infiniband/hw/i40iw/i40iw_hw.c | 4 +- drivers/infiniband/hw/i40iw/i40iw_utils.c | 59 ++++------------------- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 31 ++++++++---- drivers/infiniband/hw/i40iw/i40iw_verbs.h | 3 +- 6 files changed, 45 insertions(+), 71 deletions(-)
drivers/infiniband/hw/i40iw/i40iw.h +4 -5
@@ -409,8 +409,8 @@ static inline struct i40iw_qp *to_iwqp(struct ib_qp *ibqp) }/* i40iw.c */ -void i40iw_add_ref (struct ib_qp *); -void i40iw_rem_ref (struct ib_qp *); +void i40iw_qp_add_ref (struct ib_qp *ibqp); +void i40iw_qp_rem_ref (struct ib_qp *ibqp);struct ib_qp *i40iw_get_qp (struct ib_device *,int ); void i40iw_flush_wqes(struct i40iw_device *iwdev,
@@ -554,9 +554,8 @@ enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev, bool wait);void i40iw_receive_ilq (struct i40iw_sc_vsi *vsi,struct i40iw_puda_buf *rbuf);void i40iw_free_sqbuf (struct i40iw_sc_vsi *vsi,void *bufp); -void i40iw_free_qp_resources (struct i40iw_device *iwdev, -struct i40iw_qp *iwqp, -u32 qp_num); +void i40iw_free_qp_resources (struct i40iw_qp *iwqp); +enum i40iw_status_code i40iw_obj_aligned_mem (struct i40iw_device *iwdev,struct i40iw_dma_mem *memptr,u32 size,u32 mask);
drivers/infiniband/hw/i40iw/i40iw_cm.c +5 -5
@@ -2322,7 +2322,7 @@ static void i40iw_rem_ref_cm_node(struct i40iw_cm_node *cm_node) iwqp = cm_node->iwqp;if (iwqp) { iwqp->cm_node =NULL ; -i40iw_rem_ref (&iwqp->ibqp); +i40iw_qp_rem_ref (&iwqp->ibqp); cm_node->iwqp =NULL ; }else if (cm_node->qhash_set) {i40iw_get_addr_info (cm_node, &nfo);
@@ -3452,7 +3452,7 @@ void i40iw_cm_disconn(struct i40iw_qp *iwqp)kfree (work);return ; } -i40iw_add_ref (&iwqp->ibqp); +i40iw_qp_add_ref (&iwqp->ibqp);spin_unlock_irqrestore (&iwdev->qptable_lock, flags); work->iwqp = iwqp;
@@ -3623,7 +3623,7 @@ static void i40iw_disconnect_worker(struct work_struct *work)kfree (dwork);i40iw_cm_disconn_true (iwqp); -i40iw_rem_ref (&iwqp->ibqp); +i40iw_qp_rem_ref (&iwqp->ibqp); }/**
@@ -3745,7 +3745,7 @@ int i40iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) cm_node->lsmm_size = accept.size + conn_param->private_data_len;i40iw_cm_init_tsa_conn (iwqp, cm_node); cm_id->add_ref (cm_id); -i40iw_add_ref (&iwqp->ibqp); +i40iw_qp_add_ref (&iwqp->ibqp); attr.qp_state =IB_QPS_RTS ; cm_node->qhash_set = false;
@@ -3908,7 +3908,7 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) iwqp->cm_node = cm_node; cm_node->iwqp = iwqp; iwqp->cm_id = cm_id; -i40iw_add_ref (&iwqp->ibqp); +i40iw_qp_add_ref (&iwqp->ibqp);if (cm_node->state !=I40IW_CM_STATE_OFFLOADED ) { cm_node->state =I40IW_CM_STATE_SYN_SENT ;
drivers/infiniband/hw/i40iw/i40iw_hw.c +2 -2
@@ -313,7 +313,7 @@ void i40iw_process_aeq(struct i40iw_device *iwdev) __func__, info->qp_cq_id);continue ; } -i40iw_add_ref (&iwqp->ibqp); +i40iw_qp_add_ref (&iwqp->ibqp);spin_unlock_irqrestore (&iwdev->qptable_lock, flags); qp = &iwqp->sc_qp;spin_lock_irqsave (&iwqp->lock, flags);
@@ -427,7 +427,7 @@ void i40iw_process_aeq(struct i40iw_device *iwdev)break ; }if (info->qp) -i40iw_rem_ref (&iwqp->ibqp); +i40iw_qp_rem_ref (&iwqp->ibqp); }while (1 );if (aeqcnt)
drivers/infiniband/hw/i40iw/i40iw_utils.c +10 -49
114 lines not on this page · raw message
drivers/infiniband/hw/i40iw/i40iw_verbs.c +22 -9
@@ -364,11 +364,11 @@ static struct i40iw_pbl *i40iw_get_pbl(unsigned long va,* @iwqp: qp ptr (user or kernel) * @qp_num: qp number assigned */ -void i40iw_free_qp_resources (struct i40iw_device *iwdev, -struct i40iw_qp *iwqp, -u32 qp_num) +void i40iw_free_qp_resources (struct i40iw_qp *iwqp) {struct i40iw_pbl *iwpbl = &iwqp->iwpbl; +struct i40iw_device *iwdev = iwqp->iwdev; +u32 qp_num = iwqp->ibqp.qp_num;i40iw_ieq_cleanup_qp (iwdev->vsi.ieq, &iwqp->sc_qp);i40iw_dealloc_push_page (iwdev, &iwqp->sc_qp);
@@ -402,6 +402,10 @@ static void i40iw_clean_cqes(struct i40iw_qp *iwqp, struct i40iw_cq *iwcq)static int i40iw_destroy_qp (struct ib_qp *ibqp,struct ib_udata *udata) {struct i40iw_qp *iwqp =to_iwqp (ibqp); +struct ib_qp_attr attr; +struct i40iw_device *iwdev = iwqp->iwdev; + +memset (&attr,0 ,sizeof (attr)); iwqp->destroyed =1 ;
@@ -416,7 +420,15 @@ static int i40iw_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) } } -i40iw_rem_ref (&iwqp->ibqp); + attr.qp_state =IB_QPS_ERR ; +i40iw_modify_qp (&iwqp->ibqp, &attr,IB_QP_STATE ,NULL ); +i40iw_qp_rem_ref (&iwqp->ibqp); +wait_for_completion (&iwqp->free_qp); +i40iw_cqp_qp_destroy_cmd (&iwdev->sc_dev, &iwqp->sc_qp); +i40iw_rem_pdusecount (iwqp->iwpd, iwdev); +i40iw_free_qp_resources (iwqp); +i40iw_rem_devusecount (iwdev); +return 0 ; }
@@ -577,6 +589,7 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, qp->back_qp = (void *)iwqp; qp->push_idx =I40IW_INVALID_PUSH_PAGE_INDEX ; + iwqp->iwdev = iwdev; iwqp->ctx_info.iwarp_info = &iwqp->iwarp_info; if (i40iw_allocate_dma_mem(dev->hw,
@@ -601,7 +614,6 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, goto error; } - iwqp->iwdev = iwdev; iwqp->iwpd = iwpd; iwqp->ibqp.qp_num = qp_num; qp = &iwqp->sc_qp;
@@ -715,7 +727,7 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, goto error; } -i40iw_add_ref (&iwqp->ibqp); +refcount_set (&iwqp->refcount,1 );spin_lock_init (&iwqp->lock); iwqp->sig_all = (init_attr->sq_sig_type ==IB_SIGNAL_ALL_WR ) ?1 :0 ; iwdev->qp_table[qp_num] = iwqp;
@@ -737,10 +749,11 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, }init_completion (&iwqp->sq_drained);init_completion (&iwqp->rq_drained); +init_completion (&iwqp->free_qp);return &iwqp->ibqp; error: -i40iw_free_qp_resources (iwdev, iwqp, qp_num); +i40iw_free_qp_resources (iwqp);return ERR_PTR (err_code); }
@@ -2657,13 +2670,13 @@ static const struct ib_device_ops i40iw_dev_ops = { .get_hw_stats = i40iw_get_hw_stats, .get_port_immutable = i40iw_port_immutable, .iw_accept = i40iw_accept, - .iw_add_ref = i40iw_add_ref, + .iw_add_ref = i40iw_qp_add_ref, .iw_connect = i40iw_connect, .iw_create_listen = i40iw_create_listen, .iw_destroy_listen = i40iw_destroy_listen, .iw_get_qp = i40iw_get_qp, .iw_reject = i40iw_reject, - .iw_rem_ref = i40iw_rem_ref, + .iw_rem_ref = i40iw_qp_rem_ref, .map_mr_sg = i40iw_map_mr_sg, .mmap = i40iw_mmap, .modify_qp = i40iw_modify_qp,
drivers/infiniband/hw/i40iw/i40iw_verbs.h +2 -1
@@ -139,7 +139,7 @@ struct i40iw_qp {struct i40iw_qp_host_ctx_info ctx_info;struct i40iwarp_offload_info iwarp_info;void *allocated_buffer; -atomic_t refcount; +refcount_t refcount;struct iw_cm_id *cm_id;void *cm_node;struct ib_mr *lsmm_mr;
@@ -174,5 +174,6 @@ struct i40iw_qp {struct i40iw_dma_mem ietf_mem;struct completion sq_drained;struct completion rq_drained; + struct completion free_qp; };#endif
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 382/633 perf stat: Skip duration_time in setup_system_wide
In reply to Greg Kroah-HartmanFrom: Jin Yao <[email protected]>
[ Upstream commit 002a3d690f95804bdef6b70b26154103518e13d9 ]
Some metrics (such as DRAM_BW_Use) consists of uncore events and duration_time. For uncore events, counter->core.system_wide is true. But for duration_time, counter->core.system_wide is false so target.system_wide is set to false.
Then 'enable_on_exec' is set in perf_event_attr of uncore event. Kernel will return error when trying to open the uncore event.
This patch skips the duration_time in setup_system_wide then target.system_wide will be set to true for the evlist of uncore events + duration_time.
Before (tested on skylake desktop):
# perf stat -M DRAM_BW_Use -- sleep 1 Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (arb/event=0x84,umask=0x1/). /bin/dmesg | grep -i perf may provide additional information.
After:
# perf stat -M DRAM_BW_Use -- sleep 1
Performance counter stats for 'system wide':
169 arb/event=0x84,umask=0x1/ # 0.00 DRAM_BW_Use
40,427 arb/event=0x81,umask=0x1/
1,000,902,197 ns duration_time1.000902197 seconds time elapsed
--- tools/perf/builtin-stat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/builtin-stat.c +3 -1
@@ -1963,8 +1963,10 @@ static void setup_system_wide(int forks)struct evsel *counter;evlist__for_each_entry (evsel_list, counter) { -if (!counter->core.system_wide) +if (!counter->core.system_wide && +strcmp (counter->name,"duration_time" )) {return ; + } }if (evsel_list->core.nr_entries)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 383/633 RDMA/hns: Add check for the validity of sl configuration
In reply to Greg Kroah-HartmanFrom: Jiaran Zhang <[email protected]>
[ Upstream commit 172505cfa3a8ee98acaa569fd3be97697b333958 ]
According to the RoCE v1 specification, the sl (service level) 0-7 are mapped directly to priorities 0-7 respectively, sl 8-15 are reserved. The driver should verify whether the the value of sl is larger than 7, if so, an exception should be returned.
--- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 12 ++++++++++-- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-)
drivers/infiniband/hw/hns/hns_roce_hw_v2.c +10 -2
@@ -4287,11 +4287,19 @@ static int hns_roce_v2_set_path(struct ib_qp *ibqp, V2_QPC_BYTE_28_FL_S, 0);memcpy (context->dgid, grh->dgid.raw,sizeof (grh->dgid.raw));memset (qpc_mask->dgid,0 ,sizeof (grh->dgid.raw)); + + hr_qp->sl =rdma_ah_get_sl (&attr->ah_attr); +if (unlikely (hr_qp->sl >MAX_SERVICE_LEVEL )) { +ibdev_err (ibdev, +"failed to fill QPC, sl (%d) shouldn't be larger than %d.\n" , + hr_qp->sl,MAX_SERVICE_LEVEL ); +return -EINVAL ; + } +roce_set_field (context->byte_28_at_fl,V2_QPC_BYTE_28_SL_M , -V2_QPC_BYTE_28_SL_S ,rdma_ah_get_sl (&attr->ah_attr)); +V2_QPC_BYTE_28_SL_S , hr_qp->sl);roce_set_field (qpc_mask->byte_28_at_fl,V2_QPC_BYTE_28_SL_M ,V2_QPC_BYTE_28_SL_S ,0 ); - hr_qp->sl =rdma_ah_get_sl (&attr->ah_attr);return 0 ; }
drivers/infiniband/hw/hns/hns_roce_hw_v2.h +2 -0
@@ -1957,6 +1957,8 @@ struct hns_roce_eq_context {#define HNS_ROCE_V2_AEQE_EVENT_QUEUE_NUM_S 0#define HNS_ROCE_V2_AEQE_EVENT_QUEUE_NUM_M GENMASK(23, 0) +#define MAX_SERVICE_LEVEL 0x7 +struct hns_roce_wqe_atomic_seg {__le64 fetchadd_swap_data;__le64 cmp_data;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 384/633 RDMA/hns: Solve the overflow of the calc_pg_sz()
In reply to Greg Kroah-HartmanFrom: Jiaran Zhang <[email protected]>
[ Upstream commit 768202a0825d447de785e87ff1ea1d3c86a71727 ]
calc_pg_sz() may gets a data calculation overflow if the PAGE_SIZE is 64 KB and hop_num is 2. It is because that all variables involved in calculation are defined in type of int. So change the type of bt_chunk_size, buf_chunk_size and obj_per_chunk_default to u64.
--- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/infiniband/hw/hns/hns_roce_hw_v2.c +3 -3
@@ -1770,9 +1770,9 @@ static void calc_pg_sz(int obj_num, int obj_size, int hop_num, int ctx_bt_num, int *buf_page_size, int *bt_page_size, u32 hem_type) { u64 obj_per_chunk; -int bt_chunk_size =1 <<PAGE_SHIFT ; -int buf_chunk_size =1 <<PAGE_SHIFT ; -int obj_per_chunk_default = buf_chunk_size / obj_size; +u64 bt_chunk_size =PAGE_SIZE ; +u64 buf_chunk_size =PAGE_SIZE ; +u64 obj_per_chunk_default = buf_chunk_size / obj_size; *buf_page_size =0 ; *bt_page_size =0 ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 385/633 RDMA/hns: Fix the wrong value of rnr_retry when querying qp
In reply to Greg Kroah-HartmanFrom: Wenpeng Liang <[email protected]>
[ Upstream commit 99fcf82521d91468ee6115a3c253aa032dc63cbc ]
The rnr_retry returned to the user is not correct, it should be got from another fields in QPC.
--- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/infiniband/hw/hns/hns_roce_hw_v2.c +3 -1
@@ -4795,7 +4795,9 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, qp_attr->retry_cnt =roce_get_field (context.byte_212_lsn,V2_QPC_BYTE_212_RETRY_CNT_M ,V2_QPC_BYTE_212_RETRY_CNT_S ); - qp_attr->rnr_retry =le32_to_cpu (context.rq_rnr_timer); + qp_attr->rnr_retry =roce_get_field (context.byte_244_rnr_rxack, +V2_QPC_BYTE_244_RNR_CNT_M , +V2_QPC_BYTE_244_RNR_CNT_S ); done: qp_attr->cur_qp_state = qp_attr->qp_state;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 386/633 RDMA/hns: Fix configuration of ack_req_freq in QPC
In reply to Greg Kroah-HartmanFrom: Weihang Li <[email protected]>
[ Upstream commit fbed9d2be292504e04caa2057e3a9477a1e1d040 ]
The hardware will add AckReq flag in BTH header according to the value of ack_req_freq to request ACK from responder for the packets with this flag. It should be greater than or equal to lp_pktn_ini instead of using a fixed value.
--- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/infiniband/hw/hns/hns_roce_hw_v2.c +12 -6
@@ -3640,9 +3640,6 @@ static void modify_qp_reset_to_init(struct ib_qp *ibqp, V2_QPC_BYTE_76_SRQ_EN_S, 1); } -roce_set_field (context->byte_172_sq_psn,V2_QPC_BYTE_172_ACK_REQ_FREQ_M , -V2_QPC_BYTE_172_ACK_REQ_FREQ_S ,4 ); -roce_set_bit (context->byte_172_sq_psn,V2_QPC_BYTE_172_FRE_S ,1 ); hr_qp->access_flags = attr->qp_access_flags;
@@ -3983,6 +3980,7 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,dma_addr_t trrl_ba;dma_addr_t irrl_ba;enum ib_mtu mtu; +u8 lp_pktn_ini;u8 port_num;u64 *mtts;u8 *dmac;
@@ -4090,13 +4088,21 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp, }#define MAX_LP_MSG_LEN 65536 -/* MTU*(2^LP_PKTN_INI) shouldn't be bigger than 64kb */ +/* MTU * (2 ^ LP_PKTN_INI) shouldn't be bigger than 64KB */ + lp_pktn_ini =ilog2 (MAX_LP_MSG_LEN /ib_mtu_enum_to_int (mtu)); +roce_set_field (context->byte_56_dqpn_err,V2_QPC_BYTE_56_LP_PKTN_INI_M , -V2_QPC_BYTE_56_LP_PKTN_INI_S , -ilog2 (MAX_LP_MSG_LEN /ib_mtu_enum_to_int (mtu))); +V2_QPC_BYTE_56_LP_PKTN_INI_S , lp_pktn_ini);roce_set_field (qpc_mask->byte_56_dqpn_err,V2_QPC_BYTE_56_LP_PKTN_INI_M ,V2_QPC_BYTE_56_LP_PKTN_INI_S ,0 ); +/* ACK_REQ_FREQ should be larger than or equal to LP_PKTN_INI */ +roce_set_field (context->byte_172_sq_psn,V2_QPC_BYTE_172_ACK_REQ_FREQ_M , +V2_QPC_BYTE_172_ACK_REQ_FREQ_S , lp_pktn_ini); +roce_set_field (qpc_mask->byte_172_sq_psn, +V2_QPC_BYTE_172_ACK_REQ_FREQ_M , +V2_QPC_BYTE_172_ACK_REQ_FREQ_S ,0 ); +roce_set_bit (qpc_mask->byte_108_rx_reqepsn,V2_QPC_BYTE_108_RX_REQ_PSN_ERR_S ,0 ); roce_set_field(qpc_mask->byte_96_rx_reqmsn, V2_QPC_BYTE_96_RX_REQ_MSN_M,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 387/633 RDMA/hns: Fix missing sq_sig_type when querying QP
In reply to Greg Kroah-HartmanFrom: Weihang Li <[email protected]>
[ Upstream commit 05df49279f8926178ecb3ce88e61b63104cd6293 ]
The sq_sig_type field should be filled when querying QP, or the users may get a wrong value.
--- drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 1 + 1 file changed, 1 insertion(+)
drivers/infiniband/hw/hns/hns_roce_hw_v2.c +1 -0
@@ -4819,6 +4819,7 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, } qp_init_attr->cap = qp_attr->cap; + qp_init_attr->sq_sig_type = hr_qp->sq_signal_bits; out:mutex_unlock (&hr_qp->mutex);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 388/633 mtd: hyperbus: hbmc-am654: Fix direct mapping setup flash access
In reply to Greg Kroah-HartmanFrom: Vignesh Raghavendra <[email protected]>
[ Upstream commit aca31ce96814c84d1a41aaa109c15abe61005af7 ]
Setting up of direct mapping should be done with flash node's IO address space and not with controller's IO region.
--- drivers/mtd/hyperbus/hbmc-am654.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mtd/hyperbus/hbmc-am654.c +2 -2
@@ -70,7 +70,8 @@ static int am654_hbmc_probe(struct platform_device *pdev)platform_set_drvdata (pdev, priv); - ret =of_address_to_resource (np,0 , &res); + priv->hbdev.np =of_get_next_child (np,NULL ); + ret =of_address_to_resource (priv->hbdev.np,0 , &res);if (ret)return ret;
@@ -103,7 +104,6 @@ static int am654_hbmc_probe(struct platform_device *pdev) priv->ctlr.dev = dev; priv->ctlr.ops = &am654_hbmc_ops; priv->hbdev.ctlr = &priv->ctlr; - priv->hbdev.np =of_get_next_child (dev->of_node,NULL ); ret =hyperbus_register_device (&priv->hbdev);if (ret) {dev_err (dev,"failed to register controller\n" );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 389/633 mtd: rawnand: stm32_fmc2: fix a buffer overflow
In reply to Greg Kroah-HartmanFrom: Christophe Kerello <[email protected]>
[ Upstream commit ab16f54ef3cdb6bbc06a36f636a89e6db8a6cea3 ]
This patch solves following static checker warning:drivers/mtd/nand/raw/stm32_fmc2_nand.c:350 stm32_fmc2_nfc_select_chip()
error: buffer overflow 'nfc->data_phys_addr' 2 <= 2
The CS value can only be 0 or 1.
--- drivers/mtd/nand/raw/stm32_fmc2_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/nand/raw/stm32_fmc2_nand.c +1 -1
@@ -1791,7 +1791,7 @@ static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc,return ret; } -if (cs >FMC2_MAX_CE ) { +if (cs >=FMC2_MAX_CE ) {dev_err (nfc->dev,"invalid reg value: %d\n" , cs);return -EINVAL ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 390/633 mtd: rawnand: vf610: disable clk on error handling path in probe
In reply to Greg Kroah-HartmanFrom: Evgeny Novikov <[email protected]>
[ Upstream commit cb7dc3178a9862614b1e7567d77f4679f027a074 ]
vf610_nfc_probe() does not invoke clk_disable_unprepare() on one error handling path. The patch fixes that.
Found by Linux Driver Verification project (linuxtesting.org).
--- drivers/mtd/nand/raw/vf610_nfc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/mtd/nand/raw/vf610_nfc.c +4 -2
@@ -852,8 +852,10 @@ static int vf610_nfc_probe(struct platform_device *pdev) } of_id =of_match_device (vf610_nfc_dt_ids, &pdev->dev); -if (!of_id) -return -ENODEV ; +if (!of_id) { + err = -ENODEV ; + goto err_disable_clk; + } nfc->variant = (enum vf610_nfc_variant )of_id->data;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 391/633 mtd: spinand: gigadevice: Only one dummy byte in QUADIO
In reply to Greg Kroah-HartmanFrom: Hauke Mehrtens <[email protected]>
[ Upstream commit 6387ad9caf8f09747a8569e5876086b72ee9382c ]
The datasheet only lists one dummy byte in the 0xEH operation for the following chips:
* GD5F1GQ4xExxG
* GD5F1GQ4xFxxG
* GD5F1GQ4UAYIG
* GD5F4GQ4UAYIG
--- drivers/mtd/nand/spi/gigadevice.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mtd/nand/spi/gigadevice.c +2 -2
@@ -21,7 +21,7 @@#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4) static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),SPINAND_PAGE_READ_FROM_CACHE_X4_OP (0 ,1 ,NULL ,0 ),SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP (0 ,1 ,NULL ,0 ), SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
@@ -29,7 +29,7 @@ static SPINAND_OP_VARIANTS(read_cache_variants, SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); static SPINAND_OP_VARIANTS(read_cache_variants_f, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A (0 ,1 ,NULL ,0 ),SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP (0 ,1 ,NULL ,0 ), SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 392/633 mtd: spinand: gigadevice: Add QE Bit
In reply to Greg Kroah-HartmanFrom: Hauke Mehrtens <[email protected]>
[ Upstream commit aea7687e77bebce5b67fab9d03347bd8df7933c7 ]
The following GigaDevice chips have the QE BIT in the feature flags, I checked the datasheets, but did not try this.
* GD5F1GQ4xExxG
* GD5F1GQ4xFxxG
* GD5F1GQ4UAYIG
* GD5F4GQ4UAYIG
The Quad operations like 0xEB mention that the QE bit has to be set.
--- drivers/mtd/nand/spi/gigadevice.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/mtd/nand/spi/gigadevice.c +5 -5
@@ -202,7 +202,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, gd5fxgq4xa_ecc_get_status)), SPINAND_INFO("GD5F2GQ4xA",
@@ -212,7 +212,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, gd5fxgq4xa_ecc_get_status)), SPINAND_INFO("GD5F4GQ4xA",
@@ -222,7 +222,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, gd5fxgq4xa_ecc_get_status)), SPINAND_INFO("GD5F1GQ4UExxG",
@@ -232,7 +232,7 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - 0, + SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, gd5fxgq4uexxg_ecc_get_status)), SPINAND_INFO("GD5F1GQ4UFxxG",
@@ -242,7 +242,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {SPINAND_INFO_OP_VARIANTS (&read_cache_variants_f, &write_cache_variants, &update_cache_variants), -0 , +SPINAND_HAS_QE_BIT ,SPINAND_ECCINFO (&gd5fxgq4_variant2_ooblayout, gd5fxgq4ufxxg_ecc_get_status)), };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 393/633 mtd: rawnand: ams-delta: Fix non-OF build warning
In reply to Greg Kroah-HartmanFrom: Janusz Krzysztofik <[email protected]>
[ Upstream commit 6d11178762f7c8338a028b428198383b8978b280 ]
Commit 7c2f66a960fc ("mtd: rawnand: ams-delta: Add module device tables") introduced an OF module device table but wrapped a reference to it with of_match_ptr() which resolves to NULL in non-OF configs. That resulted in a clang compiler warning on unused variable in non-OF builds. Fix it.
drivers/mtd/nand/raw/ams-delta.c:373:34: warning: unused variable 'gpio_nand_of_id_table' [-Wunused-const-variable]
static const struct of_device_id gpio_nand_of_id_table[] = {
^1 warning generated.
--- drivers/mtd/nand/raw/ams-delta.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/mtd/nand/raw/ams-delta.c +2 -0
@@ -400,12 +400,14 @@ static int gpio_nand_remove(struct platform_device *pdev)return 0 ; } +#ifdef CONFIG_OF static const struct of_device_id gpio_nand_of_id_table[] = { {/* sentinel */ }, };MODULE_DEVICE_TABLE (of, gpio_nand_of_id_table); +#endif static const struct platform_device_id gpio_nand_plat_id_table[] = { {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 394/633 kdb: Fix pager search for multi-line strings
In reply to Greg Kroah-HartmanFrom: Daniel Thompson <[email protected]>
[ Upstream commit d081a6e353168f15e63eb9e9334757f20343319f ]
Currently using forward search doesn't handle multi-line strings correctly. The search routine replaces line breaks with \0 during the search and, for regular searches ("help | grep Common\n"), there is code after the line has been discarded or printed to replace the break character.
However during a pager search ("help\n" followed by "/Common\n") when the string is matched we will immediately return to normal output and the code that should restore the \n becomes unreachable. Fix this by restoring the replaced character when we disable the search mode and update the comment accordingly.
--- kernel/debug/kdb/kdb_io.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
kernel/debug/kdb/kdb_io.c +6 -2
@@ -706,12 +706,16 @@ int vkdb_printf(enum kdb_msgsrc src, const char *fmt, va_list ap) size_avail =sizeof (kdb_buffer) - len; goto kdb_print_out; } -if (kdb_grepping_flag >=KDB_GREPPING_FLAG_SEARCH ) +if (kdb_grepping_flag >=KDB_GREPPING_FLAG_SEARCH ) {/* * This was a interactive search (using '/' at more -* prompt) and it has completed. Clear the flag. +* prompt) and it has completed. Replace the \0 with +* its original value to ensure multi-line strings +* are handled properly, and return to normal mode. */ + *cphold = replaced_byte; kdb_grepping_flag =0 ; + }/* * at this point the string is a full line and * should be printed, up to the null.
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 395/633 overflow: Include header file with SIZE_MAX declaration
In reply to Greg Kroah-HartmanFrom: Leon Romanovsky <[email protected]>
[ Upstream commit a4947e84f23474803b62a2759b5808147e4e15f9 ]
The various array_size functions use SIZE_MAX define, but missed limits.h causes to failure to compile code that needs overflow.h.
In file included from drivers/infiniband/core/uverbs_std_types_device.c:6:
./include/linux/overflow.h: In function 'array_size':
./include/linux/overflow.h:258:10: error: 'SIZE_MAX' undeclared (first use in this function)
258 | return SIZE_MAX;
| ^~~~~~~~--- include/linux/overflow.h | 1 + 1 file changed, 1 insertion(+)
include/linux/overflow.h +1 -0
@@ -3,6 +3,7 @@#define __LINUX_OVERFLOW_H#include <linux/compiler.h> +#include <linux/limits.h> /* * In the fallback code below, we need to compute the minimum and
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 396/633 RDMA/ipoib: Set rtnl_link_ops for ipoib interfaces
In reply to Greg Kroah-HartmanFrom: Kamal Heib <[email protected]>
[ Upstream commit 5ce2dced8e95e76ff7439863a118a053a7fc6f91 ]
Report the "ipoib pkey", "mode" and "umcast" netlink attributes for every IPoiB interface type, not just children created with 'ip link add'.
After setting the rtnl_link_ops for the parent interface, implement the dellink() callback to block users from trying to remove it.
--- drivers/infiniband/ulp/ipoib/ipoib_main.c | 2 ++ drivers/infiniband/ulp/ipoib/ipoib_netlink.c | 11 +++++++++++ drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 2 ++ 3 files changed, 15 insertions(+)
drivers/infiniband/ulp/ipoib/ipoib_main.c +2 -0
@@ -2470,6 +2470,8 @@ static struct net_device *ipoib_add_port(const char *format,/* call event handler to ensure pkey in sync */ queue_work (ipoib_workqueue, &priv->flush_heavy); + ndev->rtnl_link_ops =ipoib_get_link_ops (); + result =register_netdev (ndev);if (result) { pr_warn("%s: couldn't register ipoib port %d; error %d\n",
drivers/infiniband/ulp/ipoib/ipoib_netlink.c +11 -0
@@ -144,6 +144,16 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,return 0 ; } +static void ipoib_del_child_link (struct net_device *dev,struct list_head *head) +{ +struct ipoib_dev_priv *priv =ipoib_priv (dev); + +if (!priv->parent) +return ; + +unregister_netdevice_queue (dev, head); +} +static size_t ipoib_get_size (const struct net_device *dev) { return nla_total_size(2) + /* IFLA_IPOIB_PKEY */
@@ -158,6 +168,7 @@ static struct rtnl_link_ops ipoib_link_ops __read_mostly = { .priv_size = sizeof(struct ipoib_dev_priv), .setup = ipoib_setup_common, .newlink = ipoib_new_child_link, + .dellink = ipoib_del_child_link, .changelink = ipoib_changelink, .get_size = ipoib_get_size, .fill_info = ipoib_fill_info,
drivers/infiniband/ulp/ipoib/ipoib_vlan.c +2 -0
@@ -195,6 +195,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) } priv =ipoib_priv (ndev); + ndev->rtnl_link_ops =ipoib_get_link_ops (); + result =__ipoib_vlan_add (ppriv, priv, pkey,IPOIB_LEGACY_CHILD );if (result && ndev->reg_state ==NETREG_UNINITIALIZED )
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 397/633 powerpc/64: fix irq replay missing preempt
In reply to Greg Kroah-HartmanFrom: Nicholas Piggin <[email protected]>
[ Upstream commit 903fd31d3212ab72d564c68f6cfb5d04db68773e ]
Prior to commit 3282a3da25bd ("powerpc/64: Implement soft interrupt replay in C"), replayed interrupts returned by the regular interrupt exit code, which performs preemption in case an interrupt had set need_resched.
This logic was missed by the conversion. Adding preempt_disable/enable around the interrupt replay and final irq enable will reschedule if needed.
--- arch/powerpc/kernel/irq.c | 7 +++++++ 1 file changed, 7 insertions(+)
arch/powerpc/kernel/irq.c +7 -0
@@ -368,6 +368,12 @@ notrace void arch_local_irq_restore(unsigned long mask) } } +/* +* Disable preempt here, so that the below preempt_enable will +* perform resched if required (a replayed interrupt may set +* need_resched). +*/ +preempt_disable ();irq_soft_mask_set (IRQS_ALL_DISABLED );trace_hardirqs_off ();
@@ -377,6 +383,7 @@ notrace void arch_local_irq_restore(unsigned long mask)trace_hardirqs_on ();irq_soft_mask_set (IRQS_ENABLED );__hard_irq_enable (); +preempt_enable (); }EXPORT_SYMBOL (arch_local_irq_restore);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 398/633 powerpc/64: fix irq replay pt_regs->softe value
In reply to Greg Kroah-HartmanFrom: Nicholas Piggin <[email protected]>
[ Upstream commit 2b48e96be2f9f7151197fd25dc41487054bc6f5b ]
Replayed interrupts get an "artificial" struct pt_regs constructed to pass to interrupt handler functions. This did not get the softe field set correctly, it's as though the interrupt has hit while irqs are disabled. It should be IRQS_ENABLED.
This is possibly harmless, asynchronous handlers should not be testing if irqs were disabled, but it might be possible for example some code is shared with synchronous or NMI handlers, and it makes more sense if debug output looks at this.
--- arch/powerpc/kernel/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kernel/irq.c +1 -1
@@ -214,7 +214,7 @@ void replay_soft_interrupts(void)struct pt_regs regs;ppc_save_regs (®s); - regs.softe =IRQS_ALL_DISABLED ; + regs.softe =IRQS_ENABLED ; again:if (IS_ENABLED (CONFIG_PPC_IRQ_SOFT_MASK_DEBUG ))
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 399/633 powerpc/perf: Exclude pmc5/6 from the irrelevant PMU group constraints
In reply to Greg Kroah-HartmanFrom: Athira Rajeev <[email protected]>
[ Upstream commit 3b6c3adbb2fa42749c3d38cfc4d4d0b7e096bb7b ]
PMU counter support functions enforces event constraints for group of events to check if all events in a group can be monitored. Incase of event codes using PMC5 and PMC6 ( 500fa and 600f4 respectively ), not all constraints are applicable, say the threshold or sample bits. But current code includes pmc5 and pmc6 in some group constraints (like IC_DC Qualifier bits) which is actually not applicable and hence results in those events not getting counted when scheduled along with group of other events. Patch fixes this by excluding PMC5/6 from constraints which are not relevant for it.
--- arch/powerpc/perf/isa207-common.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/powerpc/perf/isa207-common.c +10 -0
@@ -269,6 +269,15 @@ int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp) mask |=CNST_PMC_MASK (pmc); value |=CNST_PMC_VAL (pmc); + +/* +* PMC5 and PMC6 are used to count cycles and instructions and +* they do not support most of the constraint bits. Add a check +* to exclude PMC5/6 from most of the constraints except for +* EBB/BHRB. +*/ +if (pmc >=5 ) + goto ebb_bhrb; }if (pmc <=4 ) {
@@ -335,6 +344,7 @@ int isa207_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp) } } +ebb_bhrb:if (!pmc && ebb)/* EBB events must specify the PMC */ return -1 ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 400/633 powerpc/perf/hv-gpci: Fix starting index value
In reply to Greg Kroah-HartmanFrom: Kajol Jain <[email protected]>
[ Upstream commit 0f9866f7e85765bbda86666df56c92f377c3bc10 ]
Commit 9e9f60108423f ("powerpc/perf/{hv-gpci, hv-common}: generate requests with counters annotated") adds a framework for defining gpci counters.
In this patch, they adds starting_index value as '0xffffffffffffffff'. which is wrong as starting_index is of size 32 bits.
Because of this, incase we try to run hv-gpci event we get error.
In power9 machine:
command#: perf stat -e hv_gpci/system_tlbie_count_and_time_tlbie_instructions_issued/
-C 0 -I 1000
event syntax error: '..bie_count_and_time_tlbie_instructions_issued/'
\___ value too big for format, maximum is 4294967295This patch fix this issue and changes starting_index value to '0xffffffff'
After this patch:
command#: perf stat -e hv_gpci/system_tlbie_count_and_time_tlbie_instructions_issued/ -C 0 -I 1000
1.000085786 1,024 hv_gpci/system_tlbie_count_and_time_tlbie_instructions_issued/
2.000287818 1,024 hv_gpci/system_tlbie_count_and_time_tlbie_instructions_issued/
2.439113909 17,408 hv_gpci/system_tlbie_count_and_time_tlbie_instructions_issued/--- arch/powerpc/perf/hv-gpci-requests.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/powerpc/perf/hv-gpci-requests.h +3 -3
@@ -95,7 +95,7 @@ REQUEST(__field(0, 8, partition_id)#define REQUEST_NAME system_performance_capabilities#define REQUEST_NUM 0x40 -#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff" +#define REQUEST_IDX_KIND "starting_index=0xffffffff"#include I (REQUEST_BEGIN ) REQUEST(__field(0, 1, perf_collect_privileged) __field(0x1, 1, capability_mask)
@@ -223,7 +223,7 @@ REQUEST(__field(0, 2, partition_id)#define REQUEST_NAME system_hypervisor_times#define REQUEST_NUM 0xF0 -#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff" +#define REQUEST_IDX_KIND "starting_index=0xffffffff"#include I (REQUEST_BEGIN ) REQUEST(__count(0, 8, time_spent_to_dispatch_virtual_processors) __count(0x8, 8, time_spent_processing_virtual_processor_timers)
@@ -234,7 +234,7 @@ REQUEST(__count(0, 8, time_spent_to_dispatch_virtual_processors)#define REQUEST_NAME system_tlbie_count_and_time#define REQUEST_NUM 0xF4 -#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff" +#define REQUEST_IDX_KIND "starting_index=0xffffffff"#include I (REQUEST_BEGIN )REQUEST (__count (0 ,8 , tlbie_instructions_issued)/*
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 401/633 perf stat: Fix out of bounds CPU map access when handling armv8_pmu events
In reply to Greg Kroah-HartmanFrom: Namhyung Kim <[email protected]>
[ Upstream commit bef69bd7cfc363ab94b84ea29102f3e913ed3c6c ]
It was reported that 'perf stat' crashed when using with armv8_pmu (CPU) events with the task mode. As 'perf stat' uses an empty cpu map for task mode but armv8_pmu has its own cpu mask, it has confused which map it should use when accessing file descriptors and this causes segfaults:
(gdb) bt
#0 0x0000000000603fc8 in perf_evsel__close_fd_cpu (evsel=<optimized out>,
cpu=<optimized out>) at evsel.c:122
#1 perf_evsel__close_cpu (evsel=evsel@entry=0x716e950, cpu=7) at evsel.c:156
#2 0x00000000004d4718 in evlist__close (evlist=0x70a7cb0) at util/evlist.c:1242
#3 0x0000000000453404 in __run_perf_stat (argc=3, argc@entry=1, argv=0x30,
argv@entry=0xfffffaea2f90, run_idx=119, run_idx@entry=1701998435)
at builtin-stat.c:929
#4 0x0000000000455058 in run_perf_stat (run_idx=1701998435, argv=0xfffffaea2f90,
argc=1) at builtin-stat.c:947
#5 cmd_stat (argc=1, argv=0xfffffaea2f90) at builtin-stat.c:2357
#6 0x00000000004bb888 in run_builtin (p=p@entry=0x9764b8 <commands+288>,
argc=argc@entry=4, argv=argv@entry=0xfffffaea2f90) at perf.c:312
#7 0x00000000004bbb54 in handle_internal_command (argc=argc@entry=4,
argv=argv@entry=0xfffffaea2f90) at perf.c:364 #8 0x0000000000435378 in run_argv (argcp=<synthetic pointer>,
argv=<synthetic pointer>) at perf.c:408
#9 main (argc=4, argv=0xfffffaea2f90) at perf.c:538
To fix this, I simply used the given cpu map unless the evsel actually is not a system-wide event (like uncore events).
--- tools/lib/perf/evlist.c | 3 +++ 1 file changed, 3 insertions(+)
tools/lib/perf/evlist.c +3 -0
@@ -45,6 +45,9 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,if (!evsel->own_cpus || evlist->has_user_cpus) {perf_cpu_map__put (evsel->cpus); evsel->cpus =perf_cpu_map__get (evlist->cpus); + }else if (!evsel->system_wide &&perf_cpu_map__empty (evlist->cpus)) { +perf_cpu_map__put (evsel->cpus); + evsel->cpus =perf_cpu_map__get (evlist->cpus); }else if (evsel->cpus != evsel->own_cpus) {perf_cpu_map__put (evsel->cpus); evsel->cpus =perf_cpu_map__get (evsel->own_cpus);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 402/633 i3c: master: Fix error return in cdns_i3c_master_probe()
In reply to Greg Kroah-HartmanFrom: Jing Xiangfeng <[email protected]>
[ Upstream commit abea14bfdebbe9bd02f2ad24a1f3a878ed21c8f0 ]
Fix to return negative error code -ENOMEM from the error handling case instead of 0.
--- drivers/i3c/master/i3c-master-cdns.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/i3c/master/i3c-master-cdns.c +3 -1
@@ -1635,8 +1635,10 @@ static int cdns_i3c_master_probe(struct platform_device *pdev) master->ibi.slots =devm_kcalloc (&pdev->dev, master->ibi.num_slots,sizeof (*master->ibi.slots),GFP_KERNEL ); -if (!master->ibi.slots) +if (!master->ibi.slots) { + ret = -ENOMEM ; goto err_disable_sysclk; + }writel (IBIR_THR (1 ), master->regs +CMD_IBI_THR_CTRL );writel (MST_INT_IBIR_THR , master->regs +MST_IER );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 403/633 powerpc/papr_scm: Add PAPR command family to pass-through command-set
In reply to Greg Kroah-HartmanFrom: Vaibhav Jain <[email protected]>
[ Upstream commit 13135b461cf205941308984bd3271ec7d403dc40 ]
Add NVDIMM_FAMILY_PAPR to the list of valid 'dimm_family_mask' acceptable by papr_scm. This is needed as since commit 92fe2aa859f5 ("libnvdimm: Validate command family indices") libnvdimm performs a validation of 'nd_cmd_pkg.nd_family' received as part of ND_CMD_CALL processing to ensure only known command families can use the general ND_CMD_CALL pass-through functionality.
Without this change the ND_CMD_CALL pass-through targeting NVDIMM_FAMILY_PAPR error out with -EINVAL.
--- arch/powerpc/platforms/pseries/papr_scm.c | 3 +++ 1 file changed, 3 insertions(+)
arch/powerpc/platforms/pseries/papr_scm.c +3 -0
@@ -702,6 +702,9 @@ static int papr_scm_nvdimm_init(struct papr_scm_priv *p) p->bus_desc.of_node = p->pdev->dev.of_node; p->bus_desc.provider_name =kstrdup (p->pdev->name,GFP_KERNEL ); +/* Set the dimm command family mask to accept PDSMs */ +set_bit (NVDIMM_FAMILY_PAPR , &p->bus_desc.dimm_family_mask); +if (!p->bus_desc.provider_name)return -ENOMEM ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 404/633 cpufreq: powernv: Fix frame-size-overflow in powernv_cpufreq_reboot_notifier
In reply to Greg Kroah-HartmanFrom: Srikar Dronamraju <[email protected]>
[ Upstream commit a2d0230b91f7e23ceb5d8fb6a9799f30517ec33a ]
The patch avoids allocating cpufreq_policy on stack hence fixing frame size overflow in 'powernv_cpufreq_reboot_notifier':
drivers/cpufreq/powernv-cpufreq.c: In function powernv_cpufreq_reboot_notifier:
drivers/cpufreq/powernv-cpufreq.c:906:1: error: the frame size of 2064 bytes is larger than 2048 bytes
--- drivers/cpufreq/powernv-cpufreq.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/cpufreq/powernv-cpufreq.c +6 -3
@@ -884,12 +884,15 @@ static int powernv_cpufreq_reboot_notifier(struct notifier_block *nb, unsigned long action, void *unused) { int cpu; -struct cpufreq_policy cpu_policy; +struct cpufreq_policy *cpu_policy; rebooting = true;for_each_online_cpu (cpu) { -cpufreq_get_policy (&cpu_policy, cpu); -powernv_cpufreq_target_index (&cpu_policy,get_nominal_index ()); + cpu_policy =cpufreq_cpu_get (cpu); +if (!cpu_policy) +continue ; +powernv_cpufreq_target_index (cpu_policy,get_nominal_index ()); +cpufreq_cpu_put (cpu_policy); }return NOTIFY_DONE ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 405/633 IB/rdmavt: Fix sizeof mismatch
In reply to Greg Kroah-HartmanFrom: Colin Ian King <[email protected]>
[ Upstream commit 8e71f694e0c819db39af2336f16eb9689f1ae53f ]
An incorrect sizeof is being used, struct rvt_ibport ** is not correct, it should be struct rvt_ibport *. Note that since ** is the same size as
* this is not causing any issues. Improve this fix by using sizeof(*rdi->ports) as this allows us to not even reference the type of the pointer. Also remove line breaks as the entire statement can fit on one line.
Addresses-Coverity: ("Sizeof not portable (SIZEOF_MISMATCH)")
--- drivers/infiniband/sw/rdmavt/vt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/infiniband/sw/rdmavt/vt.c +1 -3
@@ -95,9 +95,7 @@ struct rvt_dev_info *rvt_alloc_device(size_t size, int nports)if (!rdi)return rdi; - rdi->ports =kcalloc (nports, -sizeof (struct rvt_ibport **), -GFP_KERNEL ); + rdi->ports =kcalloc (nports,sizeof (*rdi->ports),GFP_KERNEL );if (!rdi->ports)ib_dealloc_device (&rdi->ibdev);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 406/633 RDMA/rxe: Fix skb lifetime in rxe_rcv_mcast_pkt()
In reply to Greg Kroah-HartmanFrom: Bob Pearson <[email protected]>
[ Upstream commit e7ec96fc7932f48a6d6cdd05bf82004a1a04285b ]
The changes referenced below replaced sbk_clone)_ by taking additional references, passing the skb along and then freeing the skb. This deleted the packets before they could be processed and additionally passed bad data in each packet. Since pkt is stored in skb->cb changing pkt->qp changed it for all the packets.
Replace skb_get() by sbk_clone() in rxe_rcv_mcast_pkt() for cases where multiple QPs are receiving multicast packets on the same address.
Delete kfree_skb() because the packets need to live until they have been processed by each QP. They are freed later.
--- drivers/infiniband/sw/rxe/rxe_recv.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/infiniband/sw/rxe/rxe_recv.c +12 -5
@@ -281,6 +281,8 @@ static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)struct rxe_mc_elem *mce;struct rxe_qp *qp;union ib_gid dgid; +struct sk_buff *per_qp_skb; +struct rxe_pkt_info *per_qp_pkt;int err;if (skb->protocol ==htons (ETH_P_IP ))
@@ -309,21 +311,26 @@ static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)if (err)continue ; -/* if *not* the last qp in the list -* increase the users of the skb then post to the next qp +/* for all but the last qp create a new clone of the +* skb and pass to the qp. */ if (mce->qp_list.next != &mcg->qp_list) -skb_get (skb); + per_qp_skb =skb_clone (skb,GFP_ATOMIC ); +else + per_qp_skb = skb; - pkt->qp = qp; + per_qp_pkt =SKB_TO_PKT (per_qp_skb); + per_qp_pkt->qp = qp;rxe_add_ref (qp); -rxe_rcv_pkt (pkt, skb); +rxe_rcv_pkt (per_qp_pkt, per_qp_skb); }spin_unlock_bh (&mcg->mcg_lock);rxe_drop_ref (mcg);/* drop ref from rxe_pool_get_key. */ +return ; + err1:kfree_skb (skb); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 407/633 f2fs: reject CASEFOLD inode flag without casefold feature
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
[ Upstream commit f6322f3f1212e005e7e6aa82ceb62be53030a64b ]
syzbot reported:
general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN
KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
CPU: 0 PID: 6860 Comm: syz-executor835 Not tainted 5.9.0-rc8-syzkaller #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
RIP: 0010:utf8_casefold+0x43/0x1b0 fs/unicode/utf8-core.c:107
[...]
Call Trace:
f2fs_init_casefolded_name fs/f2fs/dir.c:85 [inline]
__f2fs_setup_filename fs/f2fs/dir.c:118 [inline]
f2fs_prepare_lookup+0x3bf/0x640 fs/f2fs/dir.c:163
f2fs_lookup+0x10d/0x920 fs/f2fs/namei.c:494
__lookup_hash+0x115/0x240 fs/namei.c:1445
filename_create+0x14b/0x630 fs/namei.c:3467
user_path_create fs/namei.c:3524 [inline]
do_mkdirat+0x56/0x310 fs/namei.c:3664
do_syscall_64+0x31/0x70 arch/x86/entry/common.c:46
entry_SYSCALL_64_after_hwframe+0x44/0xa9
[...]The problem is that an inode has F2FS_CASEFOLD_FL set, but the filesystem doesn't have the casefold feature flag set, and therefore super_block::s_encoding is NULL.
Fix this by making sanity_check_inode() reject inodes that have F2FS_CASEFOLD_FL when the filesystem doesn't have the casefold feature.
--- fs/f2fs/inode.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/f2fs/inode.c +7 -0
@@ -287,6 +287,13 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)return false; } +if ((fi->i_flags &F2FS_CASEFOLD_FL ) && !f2fs_sb_has_casefold (sbi)) { +set_sbi_flag (sbi,SBI_NEED_FSCK ); +f2fs_warn (sbi,"%s: inode (ino=%lx) has casefold flag, but casefold feature is off" , + __func__, inode->i_ino); +return false; + } +if (f2fs_has_extra_attr (inode) &&f2fs_sb_has_compression (sbi) && fi->i_flags &F2FS_COMPR_FL && F2FS_FITS_IN_INODE(ri, fi->i_extra_isize,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 408/633 um: vector: Use GFP_ATOMIC under spin lock
In reply to Greg Kroah-HartmanFrom: Tiezhu Yang <[email protected]>
[ Upstream commit e4e721fe4ccb504a29d1e8d4047667557281d932 ]
Use GFP_ATOMIC instead of GFP_KERNEL under spin lock to fix possible sleep-in-atomic-context bugs.
--- arch/um/drivers/vector_kern.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/um/drivers/vector_kern.c +2 -2
@@ -1403,7 +1403,7 @@ static int vector_net_load_bpf_flash(struct net_device *dev,kfree (vp->bpf->filter); vp->bpf->filter =NULL ; }else { - vp->bpf =kmalloc (sizeof (struct sock_fprog ),GFP_KERNEL ); + vp->bpf =kmalloc (sizeof (struct sock_fprog ),GFP_ATOMIC );if (vp->bpf ==NULL ) {netdev_err (dev,"failed to allocate memory for firmware\n" ); goto flash_fail;
@@ -1415,7 +1415,7 @@ static int vector_net_load_bpf_flash(struct net_device *dev,if (request_firmware (&fw, efl->data, &vdevice->pdev.dev)) goto flash_fail; - vp->bpf->filter =kmemdup (fw->data, fw->size,GFP_KERNEL ); + vp->bpf->filter =kmemdup (fw->data, fw->size,GFP_ATOMIC );if (!vp->bpf->filter) goto free_buffer;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 409/633 um: time-travel: Fix IRQ handling in time_travel_handle_message()
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
[ Upstream commit ebef8ea2ba967026192a26f4529890893919bc57 ]
As the comment here indicates, we need to do the polling in the idle loop without blocking interrupts, since interrupts can be vhost-user messages that we must process even while in our idle loop.
I don't know why I explained one thing and implemented another, but we have indeed observed random hangs due to this, depending on the timing of the messages.
--- arch/um/kernel/time.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
arch/um/kernel/time.c +9 -5
@@ -70,13 +70,17 @@ static void time_travel_handle_message(struct um_timetravel_msg *msg,* read of the message and write of the ACK. */ if (mode !=TTMH_READ ) { +bool disabled =irqs_disabled (); + +BUG_ON (mode ==TTMH_IDLE && !disabled); + +if (disabled) +local_irq_enable ();while (os_poll (1 , &time_travel_ext_fd) !=0 ) { -if (mode ==TTMH_IDLE ) { -BUG_ON (!irqs_disabled ()); -local_irq_enable (); -local_irq_disable (); - } +/* nothing */ } +if (disabled) +local_irq_disable (); } ret =os_read_file (time_travel_ext_fd, msg,sizeof (*msg));
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 410/633 maiblox: mediatek: Fix handling of platform_get_irq() error
In reply to Greg Kroah-HartmanFrom: Krzysztof Kozlowski <[email protected]>
[ Upstream commit 558e4c36ec9f2722af4fe8ef84dc812bcdb5c43a ]
platform_get_irq() returns -ERRNO on error. In such case casting to u32 and comparing to 0 would pass the check.
--- drivers/mailbox/mtk-cmdq-mailbox.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/mailbox/mtk-cmdq-mailbox.c +3 -5
@@ -69,7 +69,7 @@ struct cmdq_task {struct cmdq {struct mbox_controller mbox;void __iomem *base; -u32 irq; +int irq;u32 thread_nr;u32 irq_mask;struct cmdq_thread *thread;
@@ -466,10 +466,8 @@ static int cmdq_probe(struct platform_device *pdev) } cmdq->irq =platform_get_irq (pdev,0 ); -if (!cmdq->irq) { -dev_err (dev,"failed to get irq\n" ); -return -EINVAL ; - } +if (cmdq->irq <0 ) +return cmdq->irq; cmdq->thread_nr = (u32 )(unsigned long )of_device_get_match_data (dev); cmdq->irq_mask =GENMASK (cmdq->thread_nr -1 ,0 );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 411/633 perf trace: Fix off by ones in memset() after realloc() in arches using libaudit
In reply to Greg Kroah-HartmanFrom: Jiri Slaby <[email protected]>
[ Upstream commit f3013f7ed465479e60c1ab1921a5718fc541cc3b ]
'perf trace ls' started crashing after commit d21cb73a9025 on !HAVE_SYSCALL_TABLE_SUPPORT configs (armv7l here) like this:
0 strlen () at ../sysdeps/arm/armv6t2/strlen.S:126
1 0xb6800780 in __vfprintf_internal (s=0xbeff9908, s@entry=0xbeff9900, format=0xa27160 "]: %s()", ap=..., mode_flags=<optimized out>) at vfprintf-internal.c:1688
...
5 0x0056ecdc in fprintf (__fmt=0xa27160 "]: %s()", __stream=<optimized out>) at /usr/include/bits/stdio2.h:100 6 trace__sys_exit (trace=trace@entry=0xbeffc710, evsel=evsel@entry=0xd968d0, event=<optimized out>, sample=sample@entry=0xbeffc3e8) at builtin-trace.c:2475 7 0x00566d40 in trace__handle_event (sample=0xbeffc3e8, event=<optimized out>, trace=0xbeffc710) at builtin-trace.c:3122
...
15 main (argc=2, argv=0xbefff6e8) at perf.c:538
It is because memset in trace__read_syscall_info zeroes wrong memory:
1) when initializing for the first time, it does not reset the last id.
2) in other cases, it resets the last id of previous buffer.
ad 1) it causes the crash above as sc->name used in the fprintf above
contains garbage.
ad 2) it sets nonexistent from true back to false for id 11 here. Not
sure, what the consequences are.
So fix it by introducing a special case for the initial initialization and do the right +1 in both cases.
--- tools/perf/builtin-trace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
tools/perf/builtin-trace.c +5 -1
@@ -1762,7 +1762,11 @@ static int trace__read_syscall_info(struct trace *trace, int id)if (table ==NULL )return -ENOMEM ; -memset (table + trace->sctbl->syscalls.max_id,0 , (id - trace->sctbl->syscalls.max_id) *sizeof (*sc)); +// Need to memset from offset 0 and +1 members if brand new +if (trace->syscalls.table ==NULL ) +memset (table,0 , (id +1 ) *sizeof (*sc)); +else +memset (table + trace->sctbl->syscalls.max_id +1 ,0 , (id - trace->sctbl->syscalls.max_id) *sizeof (*sc)); trace->syscalls.table = table; trace->sctbl->syscalls.max_id = id;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 412/633 selftests/powerpc: Fix eeh-basic.sh exit codes
In reply to Greg Kroah-HartmanFrom: Oliver O'Halloran <[email protected]>
[ Upstream commit 996f9e0f93f16211945c8d5f18f296a88cb32f91 ]
The kselftests test running infrastructure expects tests to finish with an exit code of 4 if the test decided it should be skipped. Currently eeh-basic.sh exits with the number of devices that failed to recover, so if four devices didn't recover we'll report a skip instead of a fail.
Fix this by checking if the return code is non-zero and report success and failure by returning 0 or 1 respectively. For the cases where should actually skip return 4.
--- tools/testing/selftests/powerpc/eeh/eeh-basic.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
tools/testing/selftests/powerpc/eeh/eeh-basic.sh +6 -3
@@ -1,17 +1,19 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-only +KSELFTESTS_SKIP=4 + . ./eeh-functions.sh if ! eeh_supported ; then echo "EEH not supported on this system, skipping" - exit 0; + exit $KSELFTESTS_SKIP; fi if [ ! -e "/sys/kernel/debug/powerpc/eeh_dev_check" ] && \ [ ! -e "/sys/kernel/debug/powerpc/eeh_dev_break" ] ; then echo "debugfs EEH testing files are missing. Is debugfs mounted?" - exit 1; + exit $KSELFTESTS_SKIP; fi pre_lspci=`mktemp`
@@ -84,4 +86,5 @@ echo "$failed devices failed to recover ($dev_count tested)" lspci | diff -u $pre_lspci - rm -f $pre_lspci -exit $failed +test "$failed" == 0 +exit $?
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 413/633 f2fs: wait for sysfs kobject removal before freeing f2fs_sb_info
In reply to Greg Kroah-HartmanFrom: Jamie Iles <[email protected]>
[ Upstream commit ae284d87abade58c8db7760c808f311ef1ce693c ]
syzkaller found that with CONFIG_DEBUG_KOBJECT_RELEASE=y, unmounting an f2fs filesystem could result in the following splat:
kobject: 'loop5' ((____ptrval____)): kobject_release, parent 0000000000000000 (delayed 250)
kobject: 'f2fs_xattr_entry-7:5' ((____ptrval____)): kobject_release, parent 0000000000000000 (delayed 750)
------------[ cut here ]------------ ODEBUG: free active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x98 WARNING: CPU: 0 PID: 699 at lib/debugobjects.c:485 debug_print_object+0x180/0x240 Kernel panic - not syncing: panic_on_warn set ... CPU: 0 PID: 699 Comm: syz-executor.5 Tainted: G S 5.9.0-rc8+ #101 Hardware name: linux,dummy-virt (DT) Call trace: dump_backtrace+0x0/0x4d8 show_stack+0x34/0x48 dump_stack+0x174/0x1f8 panic+0x360/0x7a0 __warn+0x244/0x2ec report_bug+0x240/0x398 bug_handler+0x50/0xc0 call_break_hook+0x160/0x1d8 brk_handler+0x30/0xc0 do_debug_exception+0x184/0x340 el1_dbg+0x48/0xb0 el1_sync_handler+0x170/0x1c8 el1_sync+0x80/0x100 debug_print_object+0x180/0x240 debug_check_no_obj_freed+0x200/0x430 slab_free_freelist_hook+0x190/0x210 kfree+0x13c/0x460 f2fs_put_super+0x624/0xa58 generic_shutdown_super+0x120/0x300 kill_block_super+0x94/0xf8 kill_f2fs_super+0x244/0x308 deactivate_locked_super+0x104/0x150 deactivate_super+0x118/0x148 cleanup_mnt+0x27c/0x3c0 __cleanup_mnt+0x28/0x38 task_work_run+0x10c/0x248 do_notify_resume+0x9d4/0x1188 work_pending+0x8/0x34c
Like the error handling for f2fs_register_sysfs(), we need to wait for the kobject to be destroyed before returning to prevent a potential use-after-free.
--- fs/f2fs/sysfs.c | 1 + 1 file changed, 1 insertion(+)
fs/f2fs/sysfs.c +1 -0
@@ -964,4 +964,5 @@ void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi) }kobject_del (&sbi->s_kobj);kobject_put (&sbi->s_kobj); +wait_for_completion (&sbi->s_kobj_unregister); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 414/633 afs: Fix rapid cell addition/removal by not using RCU on cells tree
In reply to Greg Kroah-HartmanFrom: David Howells <[email protected]>
[ Upstream commit 92e3cc91d8f51ce64a8b7c696377180953dd316e ]
There are a number of problems that are being seen by the rapidly mounting and unmounting an afs dynamic root with an explicit cell and volume specified (which should probably be rejected, but that's a separate issue):
What the tests are doing is to look up/create a cell record for the name given and then tear it down again without actually using it to try to talk to a server. This is repeated endlessly, very fast, and the new cell collides with the old one if it's not quick enough to reuse it.
It appears (as suggested by Hillf Danton) that the search through the RB tree under a read_seqbegin_or_lock() under RCU conditions isn't safe and that it's not blocking the write_seqlock(), despite taking two passes at it. He suggested that the code should take a ref on the cell it's attempting to look at - but this shouldn't be necessary until we've compared the cell names. It's possible that I'm missing a barrier somewhere.
However, using an RCU search for this is overkill, really - we only need to access the cell name in a few places, and they're places where we're may end up sleeping anyway.
Fix this by switching to an R/W semaphore instead.
Additionally, draw the down_read() call inside the function (renamed to afs_find_cell()) since all the callers were taking the RCU read lock (or should've been[*]).
[*] afs_probe_cell_name() should have been, but that doesn't appear to be involved in the bug reports.
The symptoms of this look like:
general protection fault, probably for non-canonical address 0xf27d208691691fdb: 0000 [#1] PREEMPT SMP KASAN KASAN: maybe wild-memory-access in range [0x93e924348b48fed8-0x93e924348b48fedf] ... RIP: 0010:strncasecmp lib/string.c:52 [inline] RIP: 0010:strncasecmp+0x5f/0x240 lib/string.c:43 afs_lookup_cell_rcu+0x313/0x720 fs/afs/cell.c:88 afs_lookup_cell+0x2ee/0x1440 fs/afs/cell.c:249 afs_parse_source fs/afs/super.c:290 [inline] ...
--- fs/afs/cell.c | 131 ++++++++++++++++++++-------------------------- fs/afs/dynroot.c | 21 +++----- fs/afs/internal.h | 6 +-- fs/afs/main.c | 2 +- fs/afs/super.c | 4 +- 5 files changed, 71 insertions(+), 93 deletions(-)
fs/afs/cell.c +58 -73
@@ -41,15 +41,15 @@ static void afs_set_cell_timer(struct afs_net *net, time64_t delay) }/* -* Look up and get an activation reference on a cell record under RCU -* conditions. The caller must hold the RCU read lock. +* Look up and get an activation reference on a cell record. The caller must +* hold net->cells_lock at least read-locked. */ -struct afs_cell *afs_lookup_cell_rcu (struct afs_net *net, -const char *name,unsigned int namesz) +static struct afs_cell *afs_find_cell_locked (struct afs_net *net, +const char *name,unsigned int namesz) {struct afs_cell *cell =NULL ;struct rb_node *p; -int n, seq =0 , ret =0 ; +int n;_enter ("%*.*s" , namesz, namesz, name);
@@ -58,61 +58,48 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net,if (namesz >AFS_MAXCELLNAME )return ERR_PTR (-ENAMETOOLONG ); -do { -/* Unfortunately, rbtree walking doesn't give reliable results -* under just the RCU read lock, so we have to check for -* changes. -*/ -if (cell) -afs_put_cell (net, cell); - cell =NULL ; - ret = -ENOENT ; - -read_seqbegin_or_lock (&net->cells_lock, &seq); - -if (!name) { - cell =rcu_dereference_raw (net->ws_cell); -if (cell) { -afs_get_cell (cell); - ret =0 ; -break ; - } - ret = -EDESTADDRREQ ; -continue ; - } +if (!name) { + cell = net->ws_cell; +if (!cell) +return ERR_PTR (-EDESTADDRREQ ); +afs_get_cell (cell); +return cell; + } - p =rcu_dereference_raw (net->cells.rb_node); -while (p) { - cell = rb_entry(p, struct afs_cell, net_node); - - n =strncasecmp (cell->name, name, -min_t (size_t, cell->name_len, namesz)); -if (n ==0 ) - n = cell->name_len - namesz; -if (n <0 ) { - p =rcu_dereference_raw (p->rb_left); - }else if (n >0 ) { - p =rcu_dereference_raw (p->rb_right); - }else { -if (atomic_inc_not_zero (&cell->usage)) { - ret =0 ; -break ; - } -/* We want to repeat the search, this time with -* the lock properly locked. -*/ - } - cell =NULL ; - } + p = net->cells.rb_node; +while (p) { + cell = rb_entry(p, struct afs_cell, net_node); - }while (need_seqretry (&net->cells_lock, seq)); + n =strncasecmp (cell->name, name, +min_t (size_t, cell->name_len, namesz)); +if (n ==0 ) + n = cell->name_len - namesz; +if (n <0 ) + p = p->rb_left; +else if (n >0 ) + p = p->rb_right; +else + goto found; + } + +return ERR_PTR (-ENOENT ); -done_seqretry (&net->cells_lock, seq); +found: +if (!atomic_inc_not_zero (&cell->usage)) +return ERR_PTR (-ENOENT ); -if (ret !=0 && cell) -afs_put_cell (net, cell); +return cell; +} -return ret ==0 ? cell :ERR_PTR (ret); +struct afs_cell *afs_find_cell (struct afs_net *net, +const char *name,unsigned int namesz) +{ +struct afs_cell *cell; + +down_read (&net->cells_lock); + cell =afs_find_cell_locked (net, name, namesz); +up_read (&net->cells_lock); +return cell; }/*
@@ -245,9 +232,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,_enter ("%s,%s" , name, vllist);if (!excl) { -rcu_read_lock (); - cell =afs_lookup_cell_rcu (net, name, namesz); -rcu_read_unlock (); + cell =afs_find_cell (net, name, namesz);if (!IS_ERR (cell)) goto wait_for_cell; }
@@ -268,7 +253,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,/* Find the insertion point and check to see if someone else added a * cell whilst we were allocating. */ -write_seqlock (&net->cells_lock); +down_write (&net->cells_lock); pp = &net->cells.rb_node; parent =NULL ;
@@ -293,7 +278,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,rb_link_node_rcu (&cell->net_node, parent, pp);rb_insert_color (&cell->net_node, &net->cells);atomic_inc (&net->cells_outstanding); -write_sequnlock (&net->cells_lock); +up_write (&net->cells_lock);queue_work (afs_wq, &cell->manager);
@@ -323,7 +308,7 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,afs_get_cell (cursor); ret =0 ; } -write_sequnlock (&net->cells_lock); +up_write (&net->cells_lock);kfree (candidate);if (ret ==0 ) goto wait_for_cell;
@@ -377,10 +362,10 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)afs_get_cell (new_root);/* install the new cell */ -write_seqlock (&net->cells_lock); - old_root =rcu_access_pointer (net->ws_cell); -rcu_assign_pointer (net->ws_cell, new_root); -write_sequnlock (&net->cells_lock); +down_write (&net->cells_lock); + old_root = net->ws_cell; + net->ws_cell = new_root; +up_write (&net->cells_lock);afs_put_cell (net, old_root);_leave (" = 0" );
@@ -674,12 +659,12 @@ static void afs_manage_cell(struct work_struct *work)switch (cell->state) {case AFS_CELL_INACTIVE :case AFS_CELL_FAILED : -write_seqlock (&net->cells_lock); +down_write (&net->cells_lock); usage =1 ; deleted =atomic_try_cmpxchg_relaxed (&cell->usage, &usage,0 );if (deleted)rb_erase (&cell->net_node, &net->cells); -write_sequnlock (&net->cells_lock); +up_write (&net->cells_lock);if (deleted) goto final_destruction;if (cell->state ==AFS_CELL_FAILED )
@@ -779,7 +764,7 @@ void afs_manage_cells(struct work_struct *work)* lack of use and cells whose DNS results have expired and dispatch * their managers. */ -read_seqlock_excl (&net->cells_lock); +down_read (&net->cells_lock);for (cursor =rb_first (&net->cells); cursor; cursor =rb_next (cursor)) { struct afs_cell *cell =
@@ -824,7 +809,7 @@ void afs_manage_cells(struct work_struct *work)queue_work (afs_wq, &cell->manager); } -read_sequnlock_excl (&net->cells_lock); +up_read (&net->cells_lock);/* Update the timer on the way out. We have to pass an increment on * cells_outstanding in the namespace that we are in to the timer or
@@ -854,10 +839,10 @@ void afs_cell_purge(struct afs_net *net)_enter ("" ); -write_seqlock (&net->cells_lock); - ws =rcu_access_pointer (net->ws_cell); -RCU_INIT_POINTER (net->ws_cell,NULL ); -write_sequnlock (&net->cells_lock); +down_write (&net->cells_lock); + ws = net->ws_cell; + net->ws_cell =NULL ; +up_write (&net->cells_lock);afs_put_cell (net, ws);_debug ("del timer" );
fs/afs/dynroot.c +8 -13
@@ -123,7 +123,7 @@ static int afs_probe_cell_name(struct dentry *dentry) len--; } - cell =afs_lookup_cell_rcu (net, name, len); + cell =afs_find_cell (net, name, len);if (!IS_ERR (cell)) {afs_put_cell (net, cell);return 0 ;
@@ -179,7 +179,6 @@ static struct dentry *afs_lookup_atcell(struct dentry *dentry)struct afs_cell *cell;struct afs_net *net =afs_d2net (dentry);struct dentry *ret; -unsigned int seq =0 ;char *name;int len;
@@ -191,17 +190,13 @@ static struct dentry *afs_lookup_atcell(struct dentry *dentry)if (!name) goto out_p; -rcu_read_lock (); -do { -read_seqbegin_or_lock (&net->cells_lock, &seq); - cell =rcu_dereference_raw (net->ws_cell); -if (cell) { - len = cell->name_len; -memcpy (name, cell->name, len +1 ); - } - }while (need_seqretry (&net->cells_lock, seq)); -done_seqretry (&net->cells_lock, seq); -rcu_read_unlock (); +down_read (&net->cells_lock); + cell = net->ws_cell; +if (cell) { + len = cell->name_len; +memcpy (name, cell->name, len +1 ); + } +up_read (&net->cells_lock); ret =ERR_PTR (-ENOENT );if (!cell)
fs/afs/internal.h +3 -3
@@ -263,11 +263,11 @@ struct afs_net {/* Cell database */ struct rb_root cells; -struct afs_cell __rcu *ws_cell; +struct afs_cell *ws_cell;struct work_struct cells_manager;struct timer_list cells_timer;atomic_t cells_outstanding; -seqlock_t cells_lock; +struct rw_semaphore cells_lock;struct mutex cells_alias_lock;struct mutex proc_cells_lock;
@@ -915,7 +915,7 @@ static inline bool afs_cb_is_broken(unsigned int cb_break,* cell.c */ extern int afs_cell_init (struct afs_net *,const char *); -extern struct afs_cell *afs_lookup_cell_rcu (struct afs_net *,const char *,unsigned ); +extern struct afs_cell *afs_find_cell (struct afs_net *,const char *,unsigned );extern struct afs_cell *afs_lookup_cell (struct afs_net *,const char *,unsigned ,const char *,bool );extern struct afs_cell *afs_get_cell (struct afs_cell *);
fs/afs/main.c +1 -1
@@ -78,7 +78,7 @@ static int __net_init afs_net_init(struct net *net_ns)mutex_init (&net->socket_mutex); net->cells =RB_ROOT ; -seqlock_init (&net->cells_lock); +init_rwsem (&net->cells_lock);INIT_WORK (&net->cells_manager, afs_manage_cells);timer_setup (&net->cells_timer, afs_cells_timer,0 );
fs/afs/super.c +1 -3
@@ -634,9 +634,7 @@ static int afs_init_fs_context(struct fs_context *fc) ctx->net =afs_net (fc->net_ns);/* Default to the workstation cell. */ -rcu_read_lock (); - cell =afs_lookup_cell_rcu (ctx->net,NULL ,0 ); -rcu_read_unlock (); + cell =afs_find_cell (ctx->net,NULL ,0 );if (IS_ERR (cell)) cell =NULL ; ctx->cell = cell;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 415/633 afs: Fix cell refcounting by splitting the usage counter
In reply to Greg Kroah-HartmanFrom: David Howells <[email protected]>
[ Upstream commit 88c853c3f5c0a07c5db61b494ee25152535cfeee ]
Management of the lifetime of afs_cell struct has some problems due to the usage counter being used to determine whether objects of that type are in use in addition to whether anyone might be interested in the structure.
This is made trickier by cell objects being cached for a period of time in case they're quickly reused as they hold the result of a setup process that may be slow (DNS lookups, AFS RPC ops).
Problems include the cached root volume from alias resolution pinning its parent cell record, rmmod occasionally hanging and occasionally producing assertion failures.
Fix this by splitting the count of active users from the struct reference count. Things then work as follows:
(1) The cell cache keeps +1 on the cell's activity count and this has to be dropped before the cell can be removed. afs_manage_cell() tries to exchange the 1 to a 0 with the cells_lock write-locked, and if successful, the record is removed from the net->cells.
(2) One struct ref is 'owned' by the activity count. That is put when the active count is reduced to 0 (final_destruction label).
(3) A ref can be held on a cell whilst it is queued for management on a work queue without confusing the active count. afs_queue_cell() is added to wrap this.
(4) The queue's ref is dropped at the end of the management. This is split out into a separate function, afs_manage_cell_work().
(5) The root volume record is put after a cell is removed (at the final_destruction label) rather then in the RCU destruction routine.
(6) Volumes hold struct refs, but aren't active users.
(7) Both counts are displayed in /proc/net/afs/cells.
There are some management function changes:
(*) afs_put_cell() now just decrements the refcount and triggers the RCU
destruction if it becomes 0. It no longer sets a timer to have the manager do this.
(*) afs_use_cell() and afs_unuse_cell() are added to increase and decrease
the active count. afs_unuse_cell() sets the management timer.
(*) afs_queue_cell() is added to queue a cell with approprate refs.
There are also some other fixes:
(*) Don't let /proc/net/afs/cells access a cell's vllist if it's NULL.
(*) Make sure that candidate cells in lookups are properly destroyed
rather than being simply kfree'd. This ensures the bits it points to are destroyed also.
(*) afs_dec_cells_outstanding() is now called in cell destruction rather
than at "final_destruction". This ensures that cell->net is still valid to the end of the destructor.
(*) As a consequence of the previous two changes, move the increment of
net->cells_outstanding that was at the point of insertion into the tree to the allocation routine to correctly balance things.
--- fs/afs/cell.c | 149 +++++++++++++++++++++++++++++++-------------- fs/afs/dynroot.c | 2 +- fs/afs/internal.h | 8 ++- fs/afs/mntpt.c | 4 +- fs/afs/proc.c | 23 ++++--- fs/afs/super.c | 12 ++-- fs/afs/vl_alias.c | 8 +-- fs/afs/vl_rotate.c | 2 +- fs/afs/volume.c | 4 +- 9 files changed, 136 insertions(+), 76 deletions(-)
fs/afs/cell.c +103 -46
@@ -19,7 +19,7 @@ static unsigned __read_mostly afs_cell_gc_delay = 10;static unsigned __read_mostly afs_cell_min_ttl =10 *60 ;static unsigned __read_mostly afs_cell_max_ttl =24 *60 *60 ; -static void afs_manage_cell (struct work_struct *); +static void afs_manage_cell_work (struct work_struct *);static void afs_dec_cells_outstanding (struct afs_net *net) {
@@ -62,8 +62,7 @@ static struct afs_cell *afs_find_cell_locked(struct afs_net *net, cell = net->ws_cell;if (!cell)return ERR_PTR (-EDESTADDRREQ ); -afs_get_cell (cell); -return cell; + goto found; } p = net->cells.rb_node;
@@ -85,12 +84,12 @@ static struct afs_cell *afs_find_cell_locked(struct afs_net *net,return ERR_PTR (-ENOENT ); found: -if (!atomic_inc_not_zero (&cell->usage)) -return ERR_PTR (-ENOENT ); - -return cell; +return afs_use_cell (cell); } +/* +* Look up and get an activation reference on a cell record. +*/ struct afs_cell *afs_find_cell (struct afs_net *net,const char *name,unsigned int namesz) {
@@ -153,8 +152,9 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, cell->name[i] =tolower (name[i]); cell->name[i] =0 ; -atomic_set (&cell->usage,2 ); -INIT_WORK (&cell->manager, afs_manage_cell); +atomic_set (&cell->ref,1 ); +atomic_set (&cell->active,0 ); +INIT_WORK (&cell->manager, afs_manage_cell_work); cell->volumes =RB_ROOT ;INIT_HLIST_HEAD (&cell->proc_volumes);seqlock_init (&cell->volume_lock);
@@ -193,6 +193,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, cell->dns_source = vllist->source; cell->dns_status = vllist->status;smp_store_release (&cell->dns_lookup_count,1 );/* vs source/status */ +atomic_inc (&net->cells_outstanding);_leave (" = %p" , cell);return cell;
@@ -275,12 +276,12 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, cell = candidate; candidate =NULL ; +atomic_set (&cell->active,2 );rb_link_node_rcu (&cell->net_node, parent, pp);rb_insert_color (&cell->net_node, &net->cells); -atomic_inc (&net->cells_outstanding);up_write (&net->cells_lock); -queue_work (afs_wq, &cell->manager); +afs_queue_cell (cell); wait_for_cell:_debug ("wait_for_cell" );
@@ -305,16 +306,17 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,if (excl) { ret = -EEXIST ; }else { -afs_get_cell (cursor); +afs_use_cell (cursor); ret =0 ; }up_write (&net->cells_lock); -kfree (candidate); +if (candidate) +afs_put_cell (candidate);if (ret ==0 ) goto wait_for_cell; goto error_noput; error: -afs_put_cell (net, cell); +afs_unuse_cell (net, cell); error_noput:_leave (" = %d [error]" , ret);return ERR_PTR (ret);
@@ -359,7 +361,7 @@ int afs_cell_init(struct afs_net *net, const char *rootcell) }if (!test_and_set_bit (AFS_CELL_FL_NO_GC , &new_root->flags)) -afs_get_cell (new_root); +afs_use_cell (new_root);/* install the new cell */ down_write (&net->cells_lock);
@@ -367,7 +369,7 @@ int afs_cell_init(struct afs_net *net, const char *rootcell) net->ws_cell = new_root;up_write (&net->cells_lock); -afs_put_cell (net, old_root); +afs_unuse_cell (net, old_root);_leave (" = 0" );return 0 ; }
@@ -473,18 +475,21 @@ static int afs_update_cell(struct afs_cell *cell)static void afs_cell_destroy (struct rcu_head *rcu) { struct afs_cell *cell = container_of(rcu, struct afs_cell, rcu); +struct afs_net *net = cell->net; +int u;_enter ("%p{%s}" , cell, cell->name); - ASSERTCMP(atomic_read(&cell->usage), ==, 0); + u =atomic_read (&cell->ref); + ASSERTCMP(u, ==, 0); -afs_put_volume (cell->net, cell->root_volume, afs_volume_trace_put_cell_root); -afs_put_vlserverlist (cell->net,rcu_access_pointer (cell->vl_servers)); -afs_put_cell (cell->net, cell->alias_of); +afs_put_vlserverlist (net,rcu_access_pointer (cell->vl_servers)); +afs_unuse_cell (net, cell->alias_of);key_put (cell->anonymous_key);kfree (cell->name);kfree (cell); +afs_dec_cells_outstanding (net);_leave (" [destroyed]" ); }
@@ -519,16 +524,50 @@ void afs_cells_timer(struct timer_list *timer)*/ struct afs_cell *afs_get_cell (struct afs_cell *cell) { -atomic_inc (&cell->usage); +if (atomic_read (&cell->ref) <=0 ) +BUG (); + +atomic_inc (&cell->ref);return cell; }/* * Drop a reference on a cell record. */ -void afs_put_cell (struct afs_net *net,struct afs_cell *cell) +void afs_put_cell (struct afs_cell *cell) +{ +if (cell) { +unsigned int u, a; + + u =atomic_dec_return (&cell->ref); +if (u ==0 ) { + a =atomic_read (&cell->active); +WARN (a !=0 ,"Cell active count %u > 0\n" , a); +call_rcu (&cell->rcu, afs_cell_destroy); + } + } +} + +/* +* Note a cell becoming more active. +*/ +struct afs_cell *afs_use_cell (struct afs_cell *cell) +{ +if (atomic_read (&cell->ref) <=0 ) +BUG (); + +atomic_inc (&cell->active); +return cell; +} + +/* +* Record a cell becoming less active. When the active counter reaches 1, it +* is scheduled for destruction, but may get reactivated. +*/ +void afs_unuse_cell (struct afs_net *net,struct afs_cell *cell) {time64_t now, expire_delay; +int a;if (!cell)return ;
@@ -541,11 +580,21 @@ void afs_put_cell(struct afs_net *net, struct afs_cell *cell)if (cell->vl_servers->nr_servers) expire_delay = afs_cell_gc_delay; -if (atomic_dec_return (&cell->usage) >1 ) -return ; + a =atomic_dec_return (&cell->active); +WARN_ON (a ==0 ); +if (a ==1 ) +/* 'cell' may now be garbage collected. */ +afs_set_cell_timer (net, expire_delay); +} -/* 'cell' may now be garbage collected. */ -afs_set_cell_timer (net, expire_delay); +/* +* Queue a cell for management, giving the workqueue a ref to hold. +*/ +void afs_queue_cell (struct afs_cell *cell) +{ +afs_get_cell (cell); +if (!queue_work (afs_wq, &cell->manager)) +afs_put_cell (cell); }/*
@@ -645,12 +694,11 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)* Manage a cell record, initialising and destroying it, maintaining its DNS * records. */ -static void afs_manage_cell (struct work_struct *work) +static void afs_manage_cell (struct afs_cell *cell) { - struct afs_cell *cell = container_of(work, struct afs_cell, manager);struct afs_net *net = cell->net;bool deleted; -int ret, usage; +int ret, active;_enter ("%s" , cell->name);
@@ -660,10 +708,11 @@ static void afs_manage_cell(struct work_struct *work)case AFS_CELL_INACTIVE :case AFS_CELL_FAILED :down_write (&net->cells_lock); - usage =1 ; - deleted =atomic_try_cmpxchg_relaxed (&cell->usage, &usage,0 ); -if (deleted) + active =1 ; + deleted =atomic_try_cmpxchg_relaxed (&cell->active, &active,0 ); +if (deleted) {rb_erase (&cell->net_node, &net->cells); + }up_write (&net->cells_lock);if (deleted) goto final_destruction;
@@ -688,7 +737,7 @@ static void afs_manage_cell(struct work_struct *work) goto again;case AFS_CELL_ACTIVE : -if (atomic_read (&cell->usage) >1 ) { +if (atomic_read (&cell->active) >1 ) {if (test_and_clear_bit (AFS_CELL_FL_DO_LOOKUP , &cell->flags)) { ret =afs_update_cell (cell);if (ret <0 )
@@ -701,7 +750,7 @@ static void afs_manage_cell(struct work_struct *work) goto again;case AFS_CELL_DEACTIVATING : -if (atomic_read (&cell->usage) >1 ) +if (atomic_read (&cell->active) >1 ) goto reverse_deactivation;afs_deactivate_cell (net, cell);smp_store_release (&cell->state,AFS_CELL_INACTIVE );
@@ -733,9 +782,18 @@ static void afs_manage_cell(struct work_struct *work)return ; final_destruction: -call_rcu (&cell->rcu, afs_cell_destroy); -afs_dec_cells_outstanding (net); -_leave (" [destruct %d]" ,atomic_read (&net->cells_outstanding)); +/* The root volume is pinning the cell */ +afs_put_volume (cell->net, cell->root_volume, afs_volume_trace_put_cell_root); + cell->root_volume =NULL ; +afs_put_cell (cell); +} + +static void afs_manage_cell_work (struct work_struct *work) +{ + struct afs_cell *cell = container_of(work, struct afs_cell, manager); + +afs_manage_cell (cell); +afs_put_cell (cell); }/*
@@ -769,21 +827,20 @@ void afs_manage_cells(struct work_struct *work)for (cursor =rb_first (&net->cells); cursor; cursor =rb_next (cursor)) {struct afs_cell *cell = rb_entry(cursor, struct afs_cell, net_node); -unsigned usage; +unsigned active;bool sched_cell = false; - usage =atomic_read (&cell->usage); -_debug ("manage %s %u" , cell->name, usage); + active =atomic_read (&cell->active); +_debug ("manage %s %u %u" , cell->name,atomic_read (&cell->ref), active); - ASSERTCMP(usage, >=, 1); + ASSERTCMP(active, >=, 1);if (purging) {if (test_and_clear_bit (AFS_CELL_FL_NO_GC , &cell->flags)) - usage =atomic_dec_return (&cell->usage); - ASSERTCMP(usage, ==, 1); +atomic_dec (&cell->active); } -if (usage ==1 ) { +if (active ==1 ) {struct afs_vlserver_list *vllist;time64_t expire_at = cell->last_inactive;
@@ -806,7 +863,7 @@ void afs_manage_cells(struct work_struct *work) }if (sched_cell) -queue_work (afs_wq, &cell->manager); +afs_queue_cell (cell); }up_read (&net->cells_lock);
@@ -843,7 +900,7 @@ void afs_cell_purge(struct afs_net *net) ws = net->ws_cell; net->ws_cell =NULL ;up_write (&net->cells_lock); -afs_put_cell (net, ws); +afs_unuse_cell (net, ws);_debug ("del timer" );if (del_timer_sync (&net->cells_timer))
fs/afs/dynroot.c +1 -1
@@ -125,7 +125,7 @@ static int afs_probe_cell_name(struct dentry *dentry) cell =afs_find_cell (net, name, len);if (!IS_ERR (cell)) { -afs_put_cell (net, cell); +afs_unuse_cell (net, cell);return 0 ; }
fs/afs/internal.h +6 -2
@@ -363,7 +363,8 @@ struct afs_cell {#endif time64_t dns_expiry;/* Time AFSDB/SRV record expires */ time64_t last_inactive;/* Time of last drop of usage count */ -atomic_t usage; +atomic_t ref;/* Struct refcount */ +atomic_t active;/* Active usage counter */ unsigned long flags;#define AFS_CELL_FL_NO_GC 0/* The cell was added manually, don't auto-gc */ #define AFS_CELL_FL_DO_LOOKUP 1/* DNS lookup requested */
@@ -918,8 +919,11 @@ extern int afs_cell_init(struct afs_net *, const char *);extern struct afs_cell *afs_find_cell (struct afs_net *,const char *,unsigned );extern struct afs_cell *afs_lookup_cell (struct afs_net *,const char *,unsigned ,const char *,bool ); +extern struct afs_cell *afs_use_cell (struct afs_cell *); +extern void afs_unuse_cell (struct afs_net *,struct afs_cell *);extern struct afs_cell *afs_get_cell (struct afs_cell *); -extern void afs_put_cell (struct afs_net *,struct afs_cell *); +extern void afs_put_cell (struct afs_cell *); +extern void afs_queue_cell (struct afs_cell *);extern void afs_manage_cells (struct work_struct *);extern void afs_cells_timer (struct timer_list *); extern void __net_exit afs_cell_purge(struct afs_net *);
fs/afs/mntpt.c +2 -2
@@ -88,7 +88,7 @@ static int afs_mntpt_set_params(struct fs_context *fc, struct dentry *mntpt) ctx->force = true; }if (ctx->cell) { -afs_put_cell (ctx->net, ctx->cell); +afs_unuse_cell (ctx->net, ctx->cell); ctx->cell =NULL ; }if (test_bit (AFS_VNODE_PSEUDODIR , &vnode->flags)) {
@@ -124,7 +124,7 @@ static int afs_mntpt_set_params(struct fs_context *fc, struct dentry *mntpt)char *buf;if (src_as->cell) - ctx->cell =afs_get_cell (src_as->cell); + ctx->cell =afs_use_cell (src_as->cell);if (size <2 || size >PAGE_SIZE -1 )return -EINVAL ;
fs/afs/proc.c +11 -12
@@ -38,7 +38,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)if (v ==SEQ_START_TOKEN ) {/* display header on line 1 */ -seq_puts (m,"USE TTL SV ST NAME\n" ); +seq_puts (m,"USE ACT TTL SV ST NAME\n" );return 0 ; }
@@ -46,10 +46,11 @@ static int afs_proc_cells_show(struct seq_file *m, void *v) vllist =rcu_dereference (cell->vl_servers);/* display one cell per line on subsequent lines */ -seq_printf (m,"%3u %6lld %2u %2u %s\n" , -atomic_read (&cell->usage), +seq_printf (m,"%3u %3u %6lld %2u %2u %s\n" , +atomic_read (&cell->ref), +atomic_read (&cell->active), cell->dns_expiry -ktime_get_real_seconds (), - vllist->nr_servers, + vllist ? vllist->nr_servers :0 , cell->state, cell->name);return 0 ;
@@ -128,7 +129,7 @@ static int afs_proc_cells_write(struct file *file, char *buf, size_t size) }if (test_and_set_bit (AFS_CELL_FL_NO_GC , &cell->flags)) -afs_put_cell (net, cell); +afs_unuse_cell (net, cell); }else { goto inval; }
@@ -154,13 +155,11 @@ static int afs_proc_rootcell_show(struct seq_file *m, void *v)struct afs_net *net; net =afs_seq2net_single (m); -if (rcu_access_pointer (net->ws_cell)) { -rcu_read_lock (); - cell =rcu_dereference (net->ws_cell); -if (cell) -seq_printf (m,"%s\n" , cell->name); -rcu_read_unlock (); - } +down_read (&net->cells_lock); + cell = net->ws_cell; +if (cell) +seq_printf (m,"%s\n" , cell->name); +up_read (&net->cells_lock);return 0 ; }
fs/afs/super.c +6 -6
@@ -294,7 +294,7 @@ static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) cellnamesz, cellnamesz, cellname ?: "");return PTR_ERR (cell); } -afs_put_cell (ctx->net, ctx->cell); +afs_unuse_cell (ctx->net, ctx->cell); ctx->cell = cell; }
@@ -389,8 +389,8 @@ static int afs_validate_fc(struct fs_context *fc)_debug ("switch to alias" );key_put (ctx->key); ctx->key =NULL ; - cell =afs_get_cell (ctx->cell->alias_of); -afs_put_cell (ctx->net, ctx->cell); + cell =afs_use_cell (ctx->cell->alias_of); +afs_unuse_cell (ctx->net, ctx->cell); ctx->cell = cell; goto reget_key; }
@@ -508,7 +508,7 @@ static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc)if (ctx->dyn_root) { as->dyn_root = true; }else { - as->cell =afs_get_cell (ctx->cell); + as->cell =afs_use_cell (ctx->cell); as->volume =afs_get_volume (ctx->volume, afs_volume_trace_get_alloc_sbi); }
@@ -521,7 +521,7 @@ static void afs_destroy_sbi(struct afs_super_info *as)if (as) {struct afs_net *net =afs_net (as->net_ns);afs_put_volume (net, as->volume, afs_volume_trace_put_destroy_sbi); -afs_put_cell (net, as->cell); +afs_unuse_cell (net, as->cell);put_net (as->net_ns);kfree (as); }
@@ -607,7 +607,7 @@ static void afs_free_fc(struct fs_context *fc)afs_destroy_sbi (fc->s_fs_info);afs_put_volume (ctx->net, ctx->volume, afs_volume_trace_put_free_fc); -afs_put_cell (ctx->net, ctx->cell); +afs_unuse_cell (ctx->net, ctx->cell);key_put (ctx->key);kfree (ctx); }
fs/afs/vl_alias.c +4 -4
@@ -177,7 +177,7 @@ static int afs_compare_cell_roots(struct afs_cell *cell) is_alias:rcu_read_unlock (); - cell->alias_of =afs_get_cell (p); + cell->alias_of =afs_use_cell (p);return 1 ; }
@@ -247,18 +247,18 @@ static int afs_query_for_alias(struct afs_cell *cell, struct key *key)continue ;if (p->root_volume)continue ;/* Ignore cells that have a root.cell volume. */ -afs_get_cell (p); +afs_use_cell (p);mutex_unlock (&cell->net->proc_cells_lock);if (afs_query_for_alias_one (cell, key, p) !=0 ) goto is_alias;if (mutex_lock_interruptible (&cell->net->proc_cells_lock) <0 ) { -afs_put_cell (cell->net, p); +afs_unuse_cell (cell->net, p);return -ERESTARTSYS ; } -afs_put_cell (cell->net, p); +afs_unuse_cell (cell->net, p); }mutex_unlock (&cell->net->proc_cells_lock);
fs/afs/vl_rotate.c +1 -1
@@ -45,7 +45,7 @@ static bool afs_start_vl_iteration(struct afs_vl_cursor *vc) cell->dns_expiry <= ktime_get_real_seconds()) { dns_lookup_count =smp_load_acquire (&cell->dns_lookup_count);set_bit (AFS_CELL_FL_DO_LOOKUP , &cell->flags); -queue_work (afs_wq, &cell->manager); +afs_queue_cell (cell);if (cell->dns_source ==DNS_RECORD_UNAVAILABLE ) { if (wait_var_event_interruptible(
fs/afs/volume.c +2 -2
@@ -106,7 +106,7 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,return volume; error_1: -afs_put_cell (params->net, volume->cell); +afs_put_cell (volume->cell);kfree (volume); error_0:return ERR_PTR (ret);
@@ -228,7 +228,7 @@ static void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume)afs_remove_volume_from_cell (volume);afs_put_serverlist (net,rcu_access_pointer (volume->servers)); -afs_put_cell (net, volume->cell); +afs_put_cell (volume->cell);trace_afs_volume (volume->vid,atomic_read (&volume->usage), afs_volume_trace_free);kfree_rcu (volume, rcu);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 416/633 afs: Fix cell purging with aliases
In reply to Greg Kroah-HartmanFrom: David Howells <[email protected]>
[ Upstream commit 286377f6bdf71568a4cf07104fe44006ae0dba6d ]
When the afs module is removed, one of the things that has to be done is to purge the cell database. afs_cell_purge() cancels the management timer and then starts the cell manager work item to do the purging. This does a single run through and then assumes that all cells are now purged - but this is no longer the case.
With the introduction of alias detection, a later cell in the database can now be holding an active count on an earlier cell (cell->alias_of). The purge scan passes by the earlier cell first, but this can't be got rid of until it has discarded the alias. Ordinarily, afs_unuse_cell() would handle this by setting the management timer to trigger another pass - but afs_set_cell_timer() doesn't do anything if the namespace is being removed (net->live == false). rmmod then hangs in the wait on cells_outstanding in afs_cell_purge().
Fix this by making afs_set_cell_timer() directly queue the cell manager if net->live is false. This causes additional management passes.
Queueing the cell manager increments cells_outstanding to make sure the wait won't complete until all cells are destroyed.
--- fs/afs/cell.c | 3 +++ 1 file changed, 3 insertions(+)
fs/afs/cell.c +3 -0
@@ -19,6 +19,7 @@ static unsigned __read_mostly afs_cell_gc_delay = 10;static unsigned __read_mostly afs_cell_min_ttl =10 *60 ;static unsigned __read_mostly afs_cell_max_ttl =24 *60 *60 ; +static void afs_queue_cell_manager (struct afs_net *);static void afs_manage_cell_work (struct work_struct *);static void afs_dec_cells_outstanding (struct afs_net *net)
@@ -37,6 +38,8 @@ static void afs_set_cell_timer(struct afs_net *net, time64_t delay)atomic_inc (&net->cells_outstanding);if (timer_reduce (&net->cells_timer, jiffies + delay *HZ ))afs_dec_cells_outstanding (net); + }else { +afs_queue_cell_manager (net); } }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 417/633 afs: Fix cell removal
In reply to Greg Kroah-HartmanFrom: David Howells <[email protected]>
[ Upstream commit 1d0e850a49a5b56f8f3cb51e74a11e2fedb96be6 ]
Fix cell removal by inserting a more final state than AFS_CELL_FAILED that indicates that the cell has been unpublished in case the manager is already requeued and will go through again. The new AFS_CELL_REMOVED state will just immediately leave the manager function.
Going through a second time in the AFS_CELL_FAILED state will cause it to try to remove the cell again, potentially leading to the proc list being removed.
--- fs/afs/cell.c | 16 ++++++++++------ fs/afs/internal.h | 1 + 2 files changed, 11 insertions(+), 6 deletions(-)
fs/afs/cell.c +10 -6
@@ -291,11 +291,11 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,wait_var_event (&cell->state, ({ state =smp_load_acquire (&cell->state);/* vs error */ - state ==AFS_CELL_ACTIVE || state ==AFS_CELL_FAILED ; + state ==AFS_CELL_ACTIVE || state ==AFS_CELL_REMOVED ; }));/* Check the state obtained from the wait check. */ -if (state ==AFS_CELL_FAILED ) { +if (state ==AFS_CELL_REMOVED ) { ret = cell->error; goto error; }
@@ -700,7 +700,6 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)static void afs_manage_cell (struct afs_cell *cell) {struct afs_net *net = cell->net; -bool deleted;int ret, active;_enter ("%s" , cell->name);
@@ -712,13 +711,15 @@ static void afs_manage_cell(struct afs_cell *cell)case AFS_CELL_FAILED :down_write (&net->cells_lock); active =1 ; - deleted =atomic_try_cmpxchg_relaxed (&cell->active, &active,0 ); -if (deleted) { +if (atomic_try_cmpxchg_relaxed (&cell->active, &active,0 )) {rb_erase (&cell->net_node, &net->cells); +smp_store_release (&cell->state,AFS_CELL_REMOVED ); }up_write (&net->cells_lock); -if (deleted) +if (cell->state ==AFS_CELL_REMOVED ) { +wake_up_var (&cell->state); goto final_destruction; + }if (cell->state ==AFS_CELL_FAILED ) goto done;smp_store_release (&cell->state,AFS_CELL_UNSET );
@@ -760,6 +761,9 @@ static void afs_manage_cell(struct afs_cell *cell)wake_up_var (&cell->state); goto again; +case AFS_CELL_REMOVED : + goto done; +default :break ; }
fs/afs/internal.h +1 -0
@@ -326,6 +326,7 @@ enum afs_cell_state {AFS_CELL_DEACTIVATING ,AFS_CELL_INACTIVE ,AFS_CELL_FAILED , + AFS_CELL_REMOVED, };/*
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 418/633 RDMA/rxe: Handle skb_clone() failure in rxe_recv.c
In reply to Greg Kroah-HartmanFrom: Bob Pearson <[email protected]>
[ Upstream commit 71abf20b28ff87fee6951ec2218d5ce7969c4e87 ]
If skb_clone() is unable to allocate memory for a new sk_buff this is not detected by the current code.
Check for a NULL return and continue. This is similar to other errors in this loop over QPs attached to the multicast address and consistent with the unreliable UD transport.
Addresses-Coverity-ID: 1497804: Null pointer dereferences (NULL_RETURNS)
--- drivers/infiniband/sw/rxe/rxe_recv.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/infiniband/sw/rxe/rxe_recv.c +3 -0
@@ -319,6 +319,9 @@ static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)else per_qp_skb = skb; +if (unlikely (!per_qp_skb)) +continue ; + per_qp_pkt =SKB_TO_PKT (per_qp_skb); per_qp_pkt->qp = qp;rxe_add_ref (qp);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 419/633 mm/page_owner: change split_page_owner to take a count
In reply to Greg Kroah-HartmanFrom: Matthew Wilcox (Oracle) <[email protected]>
[ Upstream commit 8fb156c9ee2db94f7127c930c89917634a1a9f56 ]
The implementation of split_page_owner() prefers a count rather than the old order of the page. When we support a variable size THP, we won't have the order at this point, but we will have the number of pages. So change the interface to what the caller and callee would prefer.
--- include/linux/page_owner.h | 6 +++--- mm/huge_memory.c | 2 +- mm/page_alloc.c | 2 +- mm/page_owner.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-)
include/linux/page_owner.h +3 -3
@@ -11,7 +11,7 @@ extern struct page_ext_operations page_owner_ops;extern void __reset_page_owner (struct page *page,unsigned int order);extern void __set_page_owner (struct page *page,unsigned int order,gfp_t gfp_mask); -extern void __split_page_owner (struct page *page,unsigned int order); +extern void __split_page_owner (struct page *page,unsigned int nr);extern void __copy_page_owner (struct page *oldpage,struct page *newpage);extern void __set_page_owner_migrate_reason (struct page *page,int reason);extern void __dump_page_owner (struct page *page);
@@ -31,10 +31,10 @@ static inline void set_page_owner(struct page *page,__set_page_owner (page, order, gfp_mask); } -static inline void split_page_owner (struct page *page,unsigned int order) +static inline void split_page_owner (struct page *page,unsigned int nr) {if (static_branch_unlikely (&page_owner_inited)) -__split_page_owner (page, order); +__split_page_owner (page, nr); }static inline void copy_page_owner (struct page *oldpage,struct page *newpage) {
mm/huge_memory.c +1 -1
@@ -2449,7 +2449,7 @@ static void __split_huge_page(struct page *page, struct list_head *list,ClearPageCompound (head); -split_page_owner (head,HPAGE_PMD_ORDER ); +split_page_owner (head,HPAGE_PMD_NR );/* See comment in __split_huge_page_tail() */ if (PageAnon (head)) {
mm/page_alloc.c +1 -1
@@ -3213,7 +3213,7 @@ void split_page(struct page *page, unsigned int order)for (i =1 ; i < (1 << order); i++)set_page_refcounted (page + i); -split_page_owner (page, order); +split_page_owner (page,1 << order); }EXPORT_SYMBOL_GPL (split_page);
mm/page_owner.c +2 -2
@@ -204,7 +204,7 @@ void __set_page_owner_migrate_reason(struct page *page, int reason) page_owner->last_migrate_reason = reason; } -void __split_page_owner (struct page *page,unsigned int order) +void __split_page_owner (struct page *page,unsigned int nr) {int i;struct page_ext *page_ext =lookup_page_ext (page);
@@ -213,7 +213,7 @@ void __split_page_owner(struct page *page, unsigned int order)if (unlikely (!page_ext))return ; -for (i =0 ; i < (1 << order); i++) { +for (i =0 ; i < nr; i++) { page_owner =get_page_owner (page_ext); page_owner->order =0 ; page_ext =page_ext_next (page_ext);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 420/633 lib/crc32.c: fix trivial typo in preprocessor condition
In reply to Greg Kroah-HartmanFrom: Tobias Jordan <[email protected]>
[ Upstream commit 904542dc56524f921a6bab0639ff6249c01e775f ]
Whether crc32_be needs a lookup table is chosen based on CRC_LE_BITS. Obviously, the _be function should be governed by the _BE_ define.
This probably never pops up as it's hard to come up with a configuration where CRC_BE_BITS isn't the same as CRC_LE_BITS and as nobody is using bitwise CRC anyway.
--- lib/crc32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
lib/crc32.c +1 -1
@@ -331,7 +331,7 @@ static inline u32 __pure crc32_be_generic(u32 crc, unsigned char const *p,return crc; } -#if CRC_LE_BITS ==1 +#if CRC_BE_BITS ==1 u32 __pure crc32_be (u32 crc,unsigned char const *p,size_t len) {return crc32_be_generic (crc, p, len,NULL ,CRC32_POLY_BE );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 421/633 ramfs: fix nommu mmap with gaps in the page cache
In reply to Greg Kroah-HartmanFrom: Matthew Wilcox (Oracle) <[email protected]>
[ Upstream commit 50b7d85680086126d7bd91dae81d57d4cb1ab6b7 ]
ramfs needs to check that pages are both physically contiguous and contiguous in the file. If the page cache happens to have, eg, page A for index 0 of the file, no page for index 1, and page A+1 for index 2, then an mmap of the first two pages of the file will succeed when it should fail.
--- fs/ramfs/file-nommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ramfs/file-nommu.c +1 -1
@@ -224,7 +224,7 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,if (!pages) goto out_free; - nr =find_get_pages (inode->i_mapping, &pgoff, lpages, pages); + nr =find_get_pages_contig (inode->i_mapping, pgoff, lpages, pages);if (nr != lpages) goto out_free_pages;/* leave if some pages were missing */
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 422/633 rapidio: fix error handling path
In reply to Greg Kroah-HartmanFrom: Souptick Joarder <[email protected]>
[ Upstream commit fa63f083b3492b5ed5332b8d7c90b03b5ef24a1d ]
rio_dma_transfer() attempts to clamp the return value of pin_user_pages_fast() to be >= 0. However, the attempt fails because nr_pages is overridden a few lines later, and restored to the undesirable -ERRNO value.
The return value is ultimately stored in nr_pages, which in turn is passed to unpin_user_pages(), which expects nr_pages >= 0, else, disaster.
Fix this by fixing the nesting of the assignment to nr_pages: nr_pages should be clamped to zero if pin_user_pages_fast() returns -ERRNO, or set to the return value of pin_user_pages_fast(), otherwise.
[[email protected]: new changelog]
--- drivers/rapidio/devices/rio_mport_cdev.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/rapidio/devices/rio_mport_cdev.c +7 -6
@@ -871,15 +871,16 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,rmcd_error ("pin_user_pages_fast err=%ld" , pinned); nr_pages =0 ; - }else + }else {rmcd_error ("pinned %ld out of %ld pages" , pinned, nr_pages); +/* +* Set nr_pages up to mean "how many pages to unpin, in +* the error handler: +*/ + nr_pages = pinned; + } ret = -EFAULT ; -/* -* Set nr_pages up to mean "how many pages to unpin, in -* the error handler: -*/ - nr_pages = pinned; goto err_pg; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 423/633 rapidio: fix the missed put_device() for rio_mport_add_riodev
In reply to Greg Kroah-HartmanFrom: Jing Xiangfeng <[email protected]>
[ Upstream commit 85094c05eeb47d195a74a25366a2db066f1c9d47 ]
rio_mport_add_riodev() misses to call put_device() when the device already exists. Add the missed function call to fix it.
--- drivers/rapidio/devices/rio_mport_cdev.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/rapidio/devices/rio_mport_cdev.c +4 -1
@@ -1680,6 +1680,7 @@ static int rio_mport_add_riodev(struct mport_cdev_priv *priv,struct rio_dev *rdev;struct rio_switch *rswitch =NULL ;struct rio_mport *mport; +struct device *dev;size_t size;u32 rval;u32 swpinfo =0 ;
@@ -1694,8 +1695,10 @@ static int rio_mport_add_riodev(struct mport_cdev_priv *priv,rmcd_debug (RDEV ,"name:%s ct:0x%x did:0x%x hc:0x%x" , dev_info.name, dev_info.comptag, dev_info.destid, dev_info.hopcount); -if (bus_find_device_by_name (&rio_bus_type,NULL , dev_info.name)) { + dev =bus_find_device_by_name (&rio_bus_type,NULL , dev_info.name); +if (dev) {rmcd_debug (RDEV ,"device %s already exists" , dev_info.name); +put_device (dev);return -EEXIST ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 424/633 mailbox: avoid timer start from callback
In reply to Greg Kroah-HartmanFrom: Jassi Brar <[email protected]>
[ Upstream commit c7dacf5b0f32957b24ef29df1207dc2cd8307743 ]
If the txdone is done by polling, it is possible for msg_submit() to start the timer while txdone_hrtimer() callback is running. If the timer needs recheduling, it could already be enqueued by the time hrtimer_forward_now() is called, leading hrtimer to loudly complain.
WARNING: CPU: 3 PID: 74 at kernel/time/hrtimer.c:932 hrtimer_forward+0xc4/0x110 CPU: 3 PID: 74 Comm: kworker/u8:1 Not tainted 5.9.0-rc2-00236-gd3520067d01c-dirty #5 Hardware name: Libre Computer AML-S805X-AC (DT) Workqueue: events_freezable_power_ thermal_zone_device_check pstate: 20000085 (nzCv daIf -PAN -UAO BTYPE=--) pc : hrtimer_forward+0xc4/0x110 lr : txdone_hrtimer+0xf8/0x118
[...]
This can be fixed by not starting the timer from the callback path. Which requires the timer reloading as long as any message is queued on the channel, and not just when current tx is not done yet.
--- drivers/mailbox/mailbox.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/mailbox/mailbox.c +7 -5
@@ -82,9 +82,12 @@ static void msg_submit(struct mbox_chan *chan) exit:spin_unlock_irqrestore (&chan->lock, flags); -if (!err && (chan->txdone_method &TXDONE_BY_POLL )) -/* kick start the timer immediately to avoid delays */ -hrtimer_start (&chan->mbox->poll_hrt,0 ,HRTIMER_MODE_REL ); +/* kick start the timer immediately to avoid delays */ +if (!err && (chan->txdone_method &TXDONE_BY_POLL )) { +/* but only if not already active */ +if (!hrtimer_active (&chan->mbox->poll_hrt)) +hrtimer_start (&chan->mbox->poll_hrt,0 ,HRTIMER_MODE_REL ); + } }static void tx_tick (struct mbox_chan *chan,int r)
@@ -122,11 +125,10 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)struct mbox_chan *chan = &mbox->chans[i];if (chan->active_req && chan->cl) { + resched = true; txdone = chan->mbox->ops->last_tx_done (chan);if (txdone)tx_tick (chan,0 ); -else - resched = true; } }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 425/633 clk: meson: axg-audio: separate axg and g12a regmap tables
In reply to Greg Kroah-HartmanFrom: Jerome Brunet <[email protected]>
[ Upstream commit cdabb1ffc7c2349b8930f752df1edcafc1d37cc1 ]
There are more differences than what we initially thought. Let's keeps things clear and separate the axg and g12a regmap tables of the audio clock controller.
--- drivers/clk/meson/axg-audio.c | 135 ++++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 8 deletions(-)
drivers/clk/meson/axg-audio.c +127 -8
@@ -1209,13 +1209,132 @@ static struct clk_hw_onecell_data sm1_audio_hw_onecell_data = { }; -/* Convenience table to populate regmap in .probe() -* Note that this table is shared between both AXG and G12A, -* with spdifout_b clocks being exclusive to G12A. Since those -* clocks are not declared within the AXG onecell table, we do not -* feel the need to have separate AXG/G12A regmap tables. -*/ +/* Convenience table to populate regmap in .probe(). */ static struct clk_regmap *const axg_clk_regmaps[] = { + &ddr_arb, + &pdm, + &tdmin_a, + &tdmin_b, + &tdmin_c, + &tdmin_lb, + &tdmout_a, + &tdmout_b, + &tdmout_c, + &frddr_a, + &frddr_b, + &frddr_c, + &toddr_a, + &toddr_b, + &toddr_c, + &loopback, + &spdifin, + &spdifout, + &resample, + &power_detect, + &mst_a_mclk_sel, + &mst_b_mclk_sel, + &mst_c_mclk_sel, + &mst_d_mclk_sel, + &mst_e_mclk_sel, + &mst_f_mclk_sel, + &mst_a_mclk_div, + &mst_b_mclk_div, + &mst_c_mclk_div, + &mst_d_mclk_div, + &mst_e_mclk_div, + &mst_f_mclk_div, + &mst_a_mclk, + &mst_b_mclk, + &mst_c_mclk, + &mst_d_mclk, + &mst_e_mclk, + &mst_f_mclk, + &spdifout_clk_sel, + &spdifout_clk_div, + &spdifout_clk, + &spdifin_clk_sel, + &spdifin_clk_div, + &spdifin_clk, + &pdm_dclk_sel, + &pdm_dclk_div, + &pdm_dclk, + &pdm_sysclk_sel, + &pdm_sysclk_div, + &pdm_sysclk, + &mst_a_sclk_pre_en, + &mst_b_sclk_pre_en, + &mst_c_sclk_pre_en, + &mst_d_sclk_pre_en, + &mst_e_sclk_pre_en, + &mst_f_sclk_pre_en, + &mst_a_sclk_div, + &mst_b_sclk_div, + &mst_c_sclk_div, + &mst_d_sclk_div, + &mst_e_sclk_div, + &mst_f_sclk_div, + &mst_a_sclk_post_en, + &mst_b_sclk_post_en, + &mst_c_sclk_post_en, + &mst_d_sclk_post_en, + &mst_e_sclk_post_en, + &mst_f_sclk_post_en, + &mst_a_sclk, + &mst_b_sclk, + &mst_c_sclk, + &mst_d_sclk, + &mst_e_sclk, + &mst_f_sclk, + &mst_a_lrclk_div, + &mst_b_lrclk_div, + &mst_c_lrclk_div, + &mst_d_lrclk_div, + &mst_e_lrclk_div, + &mst_f_lrclk_div, + &mst_a_lrclk, + &mst_b_lrclk, + &mst_c_lrclk, + &mst_d_lrclk, + &mst_e_lrclk, + &mst_f_lrclk, + &tdmin_a_sclk_sel, + &tdmin_b_sclk_sel, + &tdmin_c_sclk_sel, + &tdmin_lb_sclk_sel, + &tdmout_a_sclk_sel, + &tdmout_b_sclk_sel, + &tdmout_c_sclk_sel, + &tdmin_a_sclk_pre_en, + &tdmin_b_sclk_pre_en, + &tdmin_c_sclk_pre_en, + &tdmin_lb_sclk_pre_en, + &tdmout_a_sclk_pre_en, + &tdmout_b_sclk_pre_en, + &tdmout_c_sclk_pre_en, + &tdmin_a_sclk_post_en, + &tdmin_b_sclk_post_en, + &tdmin_c_sclk_post_en, + &tdmin_lb_sclk_post_en, + &tdmout_a_sclk_post_en, + &tdmout_b_sclk_post_en, + &tdmout_c_sclk_post_en, + &tdmin_a_sclk, + &tdmin_b_sclk, + &tdmin_c_sclk, + &tdmin_lb_sclk, + &tdmout_a_sclk, + &tdmout_b_sclk, + &tdmout_c_sclk, + &tdmin_a_lrclk, + &tdmin_b_lrclk, + &tdmin_c_lrclk, + &tdmin_lb_lrclk, + &tdmout_a_lrclk, + &tdmout_b_lrclk, + &tdmout_c_lrclk, +}; + +static struct clk_regmap *const g12a_clk_regmaps[] = { &ddr_arb, &pdm, &tdmin_a,
@@ -1713,8 +1832,8 @@ static const struct audioclk_data axg_audioclk_data = { };static const struct audioclk_data g12a_audioclk_data = { - .regmap_clks = axg_clk_regmaps, - .regmap_clk_num =ARRAY_SIZE (axg_clk_regmaps), + .regmap_clks = g12a_clk_regmaps, + .regmap_clk_num =ARRAY_SIZE (g12a_clk_regmaps), .hw_onecell_data = &g12a_audio_hw_onecell_data, .reset_offset =AUDIO_SW_RESET , .reset_num =26 ,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 426/633 rtc: ds1307: Clear OSF flag on DS1388 when setting time
In reply to Greg Kroah-HartmanFrom: Chris Packham <[email protected]>
[ Upstream commit f471b05f76e4b1b6ba07ebc7681920a5c5b97c5d ]
Ensure the OSF flag is cleared on the DS1388 when the clock is set.
--- drivers/rtc/rtc-ds1307.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/rtc/rtc-ds1307.c +4 -0
@@ -352,6 +352,10 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)regmap_update_bits (ds1307->regmap,DS1340_REG_FLAG ,DS1340_BIT_OSF ,0 );break ; +case ds_1388: +regmap_update_bits (ds1307->regmap,DS1388_REG_FLAG , +DS1388_BIT_OSF ,0 ); +break ;case mcp794xx:/* * these bits were cleared when preparing the date/time
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 427/633 i2c: rcar: Auto select RESET_CONTROLLER
In reply to Greg Kroah-HartmanFrom: Dirk Behme <[email protected]>
[ Upstream commit 5b9bacf28a973a6b16510493416baeefa2c06289 ]
The i2c-rcar driver utilizes the Generic Reset Controller kernel feature, so select the RESET_CONTROLLER option when the I2C_RCAR option is selected with a Gen3 SoC.
--- drivers/i2c/busses/Kconfig | 1 + 1 file changed, 1 insertion(+)
drivers/i2c/busses/Kconfig +1 -0
@@ -1191,6 +1191,7 @@ config I2C_RCAR tristate "Renesas R-Car I2C Controller" depends on ARCH_RENESAS || COMPILE_TEST select I2C_SLAVE + select RESET_CONTROLLER if ARCH_RCAR_GEN3 help If you say yes to this option, support will be included for the R-Car I2C controller.
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 428/633 clk: meson: g12a: mark fclk_div2 as critical
In reply to Greg Kroah-HartmanFrom: Stefan Agner <[email protected]>
[ Upstream commit 2c4e80e06790cb49ad2603855d30c5aac2209c47 ]
On Amlogic Meson G12b platform, similar to fclk_div3, the fclk_div2 seems to be necessary for the system to operate correctly as well.
Typically, the clock also gets chosen by the eMMC peripheral. This probably masked the problem so far. However, when booting from a SD card the clock seems to get disabled which leads to a system freeze.
Let's mark this clock as critical, fixing boot from SD card on G12b platforms.
--- drivers/clk/meson/g12a.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/clk/meson/g12a.c +11 -0
@@ -298,6 +298,17 @@ static struct clk_regmap g12a_fclk_div2 = { &g12a_fclk_div2_div.hw }, .num_parents = 1, +/* +* Similar to fclk_div3, it seems that this clock is used by +* the resident firmware and is required by the platform to +* operate correctly. +* Until the following condition are met, we need this clock to +* be marked as critical: +* a) Mark the clock used by a firmware resource, if possible +* b) CCF has a clock hand-off mechanism to make the sure the +* clock stays on until the proper driver comes along +*/ + .flags = CLK_IS_CRITICAL, }, };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 429/633 PCI: designware-ep: Fix the Header Type check
In reply to Greg Kroah-HartmanFrom: Hou Zhiqiang <[email protected]>
[ Upstream commit 16270a92355722e387e9ca19627c5a4d7bae1354 ]
The current check will result in the multiple function device fails to initialize. So fix the check by masking out the multiple function bit.
--- drivers/pci/controller/dwc/pcie-designware-ep.c | 3 ++- include/uapi/linux/pci_regs.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/pci/controller/dwc/pcie-designware-ep.c +2 -1
@@ -505,7 +505,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)u32 reg;int i; - hdr_type =dw_pcie_readb_dbi (pci,PCI_HEADER_TYPE ); + hdr_type =dw_pcie_readb_dbi (pci,PCI_HEADER_TYPE ) & +PCI_HEADER_TYPE_MASK ;if (hdr_type !=PCI_HEADER_TYPE_NORMAL ) { dev_err(pci->dev, "PCIe controller is not set to EP mode (hdr_type:0x%x)!\n",
include/uapi/linux/pci_regs.h +1 -0
@@ -76,6 +76,7 @@#define PCI_CACHE_LINE_SIZE 0x0c/* 8 bits */ #define PCI_LATENCY_TIMER 0x0d/* 8 bits */ #define PCI_HEADER_TYPE 0x0e/* 8 bits */ +#define PCI_HEADER_TYPE_MASK 0x7f#define PCI_HEADER_TYPE_NORMAL 0#define PCI_HEADER_TYPE_BRIDGE 1#define PCI_HEADER_TYPE_CARDBUS 2
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 430/633 PCI: aardvark: Fix compilation on s390
In reply to Greg Kroah-HartmanFrom: Pali Rohár <[email protected]>
[ Upstream commit b32c012e4b98f0126aa327be2d1f409963057643 ]
Include linux/gpio/consumer.h instead of linux/gpio.h, as is said in the latter file.
This was reported by kernel test bot when compiling for s390.
drivers/pci/controller/pci-aardvark.c:350:2: error: implicit declaration of function 'gpiod_set_value_cansleep' [-Werror,-Wimplicit-function-declaration] drivers/pci/controller/pci-aardvark.c:1074:21: error: implicit declaration of function 'devm_gpiod_get_from_of_node' [-Werror,-Wimplicit-function-declaration] drivers/pci/controller/pci-aardvark.c:1076:14: error: use of undeclared identifier 'GPIOD_OUT_LOW'
--- drivers/pci/controller/pci-aardvark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/controller/pci-aardvark.c +1 -1
@@ -9,7 +9,7 @@*/ #include <linux/delay.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqdomain.h>
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 431/633 PCI: aardvark: Check for errors from pci_bridge_emul_init() call
In reply to Greg Kroah-HartmanFrom: Pali Rohár <[email protected]>
[ Upstream commit 7862a6134456c8b4f8c39e8c94aa97e5c2f7f2b7 ]
Function pci_bridge_emul_init() may fail so correctly check for errors.
--- drivers/pci/controller/pci-aardvark.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/pci/controller/pci-aardvark.c +7 -4
@@ -608,7 +608,7 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {* Initialize the configuration space of the PCI-to-PCI bridge * associated with the given PCIe interface. */ -static void advk_sw_pci_bridge_init (struct advk_pcie *pcie) +static int advk_sw_pci_bridge_init (struct advk_pcie *pcie) {struct pci_bridge_emul *bridge = &pcie->bridge;
@@ -634,8 +634,7 @@ static void advk_sw_pci_bridge_init(struct advk_pcie *pcie) bridge->data = pcie; bridge->ops = &advk_pci_bridge_emul_ops; -pci_bridge_emul_init (bridge,0 ); - +return pci_bridge_emul_init (bridge,0 ); } static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
@@ -1169,7 +1168,11 @@ static int advk_pcie_probe(struct platform_device *pdev)advk_pcie_setup_hw (pcie); -advk_sw_pci_bridge_init (pcie); + ret =advk_sw_pci_bridge_init (pcie); +if (ret) { +dev_err (dev,"Failed to register emulated root PCI bridge\n" ); +return ret; + } ret =advk_pcie_init_irq_domain (pcie);if (ret) {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 432/633 PCI: iproc: Set affinity mask on MSI interrupts
In reply to Greg Kroah-HartmanFrom: Mark Tomlinson <[email protected]>
[ Upstream commit eb7eacaa5b9e4f665bd08d416c8f88e63d2f123c ]
The core interrupt code expects the irq_set_affinity call to update the effective affinity for the interrupt. This was not being done, so update iproc_msi_irq_set_affinity() to do so.
--- drivers/pci/controller/pcie-iproc-msi.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/pci/controller/pcie-iproc-msi.c +9 -4
@@ -209,15 +209,20 @@ static int iproc_msi_irq_set_affinity(struct irq_data *data,struct iproc_msi *msi =irq_data_get_irq_chip_data (data);int target_cpu =cpumask_first (mask);int curr_cpu; +int ret; curr_cpu =hwirq_to_cpu (msi, data->hwirq);if (curr_cpu == target_cpu) -return IRQ_SET_MASK_OK_DONE ; + ret =IRQ_SET_MASK_OK_DONE ; +else { +/* steer MSI to the target CPU */ + data->hwirq =hwirq_to_canonical_hwirq (msi, data->hwirq) + target_cpu; + ret =IRQ_SET_MASK_OK ; + } -/* steer MSI to the target CPU */ - data->hwirq =hwirq_to_canonical_hwirq (msi, data->hwirq) + target_cpu; +irq_data_update_effective_affinity (data,cpumask_of (target_cpu)); -return IRQ_SET_MASK_OK ; +return ret; } static void iproc_msi_irq_compose_msi_msg(struct irq_data *data,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 433/633 rpmsg: smd: Fix a kobj leak in in qcom_smd_parse_edge()
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
[ Upstream commit e69ee0cf655e8e0c4a80f4319e36019b74f17639 ]
We need to call of_node_put(node) on the error paths for this function.
--- drivers/rpmsg/qcom_smd.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-)
drivers/rpmsg/qcom_smd.c +22 -10
@@ -1338,7 +1338,7 @@ static int qcom_smd_parse_edge(struct device *dev, ret =of_property_read_u32 (node, key, &edge->edge_id);if (ret) {dev_err (dev,"edge missing %s property\n" , key); -return -EINVAL ; + goto put_node; } edge->remote_pid =QCOM_SMEM_HOST_ANY ;
@@ -1349,32 +1349,37 @@ static int qcom_smd_parse_edge(struct device *dev, edge->mbox_client.knows_txdone = true; edge->mbox_chan =mbox_request_channel (&edge->mbox_client,0 );if (IS_ERR (edge->mbox_chan)) { -if (PTR_ERR (edge->mbox_chan) != -ENODEV ) -return PTR_ERR (edge->mbox_chan); +if (PTR_ERR (edge->mbox_chan) != -ENODEV ) { + ret =PTR_ERR (edge->mbox_chan); + goto put_node; + } edge->mbox_chan =NULL ; syscon_np =of_parse_phandle (node,"qcom,ipc" ,0 );if (!syscon_np) {dev_err (dev,"no qcom,ipc node\n" ); -return -ENODEV ; + ret = -ENODEV ; + goto put_node; } edge->ipc_regmap =syscon_node_to_regmap (syscon_np); -if (IS_ERR (edge->ipc_regmap)) -return PTR_ERR (edge->ipc_regmap); +if (IS_ERR (edge->ipc_regmap)) { + ret =PTR_ERR (edge->ipc_regmap); + goto put_node; + } key ="qcom,ipc" ; ret =of_property_read_u32_index (node, key,1 , &edge->ipc_offset);if (ret <0 ) {dev_err (dev,"no offset in %s\n" , key); -return -EINVAL ; + goto put_node; } ret =of_property_read_u32_index (node, key,2 , &edge->ipc_bit);if (ret <0 ) {dev_err (dev,"no bit in %s\n" , key); -return -EINVAL ; + goto put_node; } }
@@ -1385,7 +1390,8 @@ static int qcom_smd_parse_edge(struct device *dev, irq =irq_of_parse_and_map (node,0 );if (irq <0 ) {dev_err (dev,"required smd interrupt missing\n" ); -return -EINVAL ; + ret = irq; + goto put_node; } ret = devm_request_irq(dev, irq,
@@ -1393,12 +1399,18 @@ static int qcom_smd_parse_edge(struct device *dev, node->name, edge);if (ret) {dev_err (dev,"failed to request smd irq\n" ); -return ret; + goto put_node; } edge->irq = irq;return 0 ; + +put_node: +of_node_put (node); + edge->of_node =NULL ; + +return ret; }/*
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 434/633 rpmsg: Avoid double-free in mtk_rpmsg_register_device
In reply to Greg Kroah-HartmanFrom: Nicolas Boichat <[email protected]>
[ Upstream commit 231331b2dbd71487159a0400d9ffd967eb0d0e08 ]
If rpmsg_register_device fails, it will call mtk_rpmsg_release_device which already frees mdev.
--- drivers/rpmsg/mtk_rpmsg.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
drivers/rpmsg/mtk_rpmsg.c +1 -8
@@ -200,7 +200,6 @@ static int mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev,struct rpmsg_device *rpdev;struct mtk_rpmsg_device *mdev;struct platform_device *pdev = mtk_subdev->pdev; -int ret; mdev =kzalloc (sizeof (*mdev),GFP_KERNEL );if (!mdev)
@@ -219,13 +218,7 @@ static int mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev, rpdev->dev.parent = &pdev->dev; rpdev->dev.release = mtk_rpmsg_release_device; - ret =rpmsg_register_device (rpdev); -if (ret) { -kfree (mdev); -return ret; - } - -return 0 ; +return rpmsg_register_device (rpdev); }static void mtk_register_device_work_function (struct work_struct *register_work)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 435/633 PCI/IOV: Mark VFs as not implementing PCI_COMMAND_MEMORY
In reply to Greg Kroah-HartmanFrom: Matthew Rosato <[email protected]>
[ Upstream commit 12856e7acde4702b7c3238c15fcba86ff6aa507f ]
For VFs, the Memory Space Enable bit in the Command Register is hard-wired to 0.
Add a new bit to signify devices where the Command Register Memory Space Enable bit does not control the device's response to MMIO accesses.
--- drivers/pci/iov.c | 1 + include/linux/pci.h | 1 + 2 files changed, 2 insertions(+)
drivers/pci/iov.c +1 -0
@@ -180,6 +180,7 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id) virtfn->device = iov->vf_device; virtfn->is_virtfn =1 ; virtfn->physfn =pci_dev_get (dev); + virtfn->no_command_memory =1 ;if (id ==0 )pci_read_vf_config_common (virtfn);
include/linux/pci.h +1 -0
@@ -439,6 +439,7 @@ struct pci_dev { unsigned int is_probed:1; /* Device probing in progress */ unsigned int link_active_reporting:1;/* Device capable of reporting link active */ unsigned int no_vf_scan:1; /* Don't scan for VFs after IOV enablement */ + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */pci_dev_flags_t dev_flags;atomic_t enable_cnt;/* pci_enable_device has been called */
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 436/633 vfio: add a singleton check for vfio_group_pin_pages
In reply to Greg Kroah-HartmanFrom: Yan Zhao <[email protected]>
[ Upstream commit 7ef32e52368f62a4e041a4f0abefb4fb64e7fd4a ]
Page pinning is used both to translate and pin device mappings for DMA purpose, as well as to indicate to the IOMMU backend to limit the dirty page scope to those pages that have been pinned, in the case of an IOMMU backed device.
To support this, the vfio_pin_pages() interface limits itself to only singleton groups such that the IOMMU backend can consider dirty page scope only at the group level. Implement the same requirement for the vfio_group_pin_pages() interface.
--- drivers/vfio/vfio.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/vfio/vfio.c +3 -0
@@ -2050,6 +2050,9 @@ int vfio_group_pin_pages(struct vfio_group *group,if (!group || !user_iova_pfn || !phys_pfn || !npage)return -EINVAL ; +if (group->dev_counter >1 ) +return -EINVAL ; +if (npage >VFIO_PIN_PAGES_MAX_ENTRIES )return -E2BIG ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 437/633 s390/pci: Mark all VFs as not implementing PCI_COMMAND_MEMORY
In reply to Greg Kroah-HartmanFrom: Matthew Rosato <[email protected]>
[ Upstream commit 08b6e22b850c28b6032da1e4d767a33116e23dfb ]
For s390 we can have VFs that are passed-through without the associated PF. Firmware provides an emulation layer to allow these devices to operate independently, but is missing emulation of the Memory Space Enable bit. For these as well as linked VFs, set no_command_memory which specifies these devices do not implement PCI_COMMAND_MEMORY.
--- arch/s390/pci/pci_bus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/s390/pci/pci_bus.c +3 -2
@@ -197,9 +197,10 @@ void pcibios_bus_add_device(struct pci_dev *pdev)* With pdev->no_vf_scan the common PCI probing code does not * perform PF/VF linking. */ -if (zdev->vfn) +if (zdev->vfn) {zpci_bus_setup_virtfn (zdev->zbus, pdev, zdev->vfn); - + pdev->no_command_memory =1 ; + } }static int zpci_bus_add_device (struct zpci_bus *zbus,struct zpci_dev *zdev)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 438/633 vfio/pci: Decouple PCI_COMMAND_MEMORY bit checks from is_virtfn
In reply to Greg Kroah-HartmanFrom: Matthew Rosato <[email protected]>
[ Upstream commit 515ecd5368f1510152fa4f9b9ce55b66ac56c334 ]
While it is true that devices with is_virtfn=1 will have a Memory Space Enable bit that is hard-wired to 0, this is not the only case where we see this behavior -- For example some bare-metal hypervisors lack Memory Space Enable bit emulation for devices not setting is_virtfn (s390). Fix this by instead checking for the newly-added no_command_memory bit which directly denotes the need for PCI_COMMAND_MEMORY emulation in vfio.
--- drivers/vfio/pci/vfio_pci_config.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
drivers/vfio/pci/vfio_pci_config.c +14 -10
@@ -406,7 +406,7 @@ bool __vfio_pci_memory_enabled(struct vfio_pci_device *vdev)* PF SR-IOV capability, there's therefore no need to trigger * faults based on the virtual value. */ -return pdev->is_virtfn || (cmd &PCI_COMMAND_MEMORY ); +return pdev->no_command_memory || (cmd &PCI_COMMAND_MEMORY ); }/*
@@ -520,8 +520,8 @@ static int vfio_basic_config_read(struct vfio_pci_device *vdev, int pos, count =vfio_default_config_read (vdev, pos, count, perm, offset, val); -/* Mask in virtual memory enable for SR-IOV devices */ -if (offset ==PCI_COMMAND && vdev->pdev->is_virtfn) { +/* Mask in virtual memory enable */ +if (offset ==PCI_COMMAND && vdev->pdev->no_command_memory) {u16 cmd =le16_to_cpu (*(__le16 *)&vdev->vconfig[PCI_COMMAND ]);u32 tmp_val =le32_to_cpu (*val);
@@ -589,9 +589,11 @@ static int vfio_basic_config_write(struct vfio_pci_device *vdev, int pos,* shows it disabled (phys_mem/io, then the device has * undergone some kind of backdoor reset and needs to be * restored before we allow it to enable the bars. -* SR-IOV devices will trigger this, but we catch them later +* SR-IOV devices will trigger this - for mem enable let's +* catch this now and for io enable it will be caught later */ -if ((new_mem && virt_mem && !phys_mem) || +if ((new_mem && virt_mem && !phys_mem && + !pdev->no_command_memory) || (new_io && virt_io && !phys_io) ||vfio_need_bar_restore (vdev))vfio_bar_restore (vdev);
@@ -1734,12 +1736,14 @@ int vfio_config_init(struct vfio_pci_device *vdev) vconfig[PCI_INTERRUPT_PIN]); vconfig[PCI_INTERRUPT_PIN ] =0 ;/* Gratuitous for good VFs */ - + } +if (pdev->no_command_memory) {/* -* VFs do no implement the memory enable bit of the COMMAND -* register therefore we'll not have it set in our initial -* copy of config space after pci_enable_device(). For -* consistency with PFs, set the virtual enable bit here. +* VFs and devices that set pdev->no_command_memory do not +* implement the memory enable bit of the COMMAND register +* therefore we'll not have it set in our initial copy of +* config space after pci_enable_device(). For consistency +* with PFs, set the virtual enable bit here. */ *(__le16 *)&vconfig[PCI_COMMAND ] |=cpu_to_le16 (PCI_COMMAND_MEMORY );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 439/633 vfio: fix a missed vfio group put in vfio_pin_pages
In reply to Greg Kroah-HartmanFrom: Yan Zhao <[email protected]>
[ Upstream commit 28b130244061863cf0437b7af1625fb45ec1a71e ]
When error occurs, need to put vfio group after a successful get.
--- drivers/vfio/vfio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/vfio/vfio.c +4 -2
@@ -1948,8 +1948,10 @@ int vfio_pin_pages(struct device *dev, unsigned long *user_pfn, int npage,if (!group)return -ENODEV ; -if (group->dev_counter >1 ) -return -EINVAL ; +if (group->dev_counter >1 ) { + ret = -EINVAL ; + goto err_pin_pages; + } ret =vfio_group_add_container_user (group);if (ret)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 440/633 vfio/type1: fix dirty bitmap calculation in vfio_dma_rw
In reply to Greg Kroah-HartmanFrom: Yan Zhao <[email protected]>
[ Upstream commit 2c5af98592f65517170c7bcc714566590d3f7397 ]
The count of dirtied pages is not only determined by count of copied pages, but also by the start offset.
e.g. if offset = PAGE_SIZE - 1, and *copied=2, the dirty pages count is 2, instead of 1 or 0.
--- drivers/vfio/vfio_iommu_type1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/vfio/vfio_iommu_type1.c +2 -1
@@ -2899,7 +2899,8 @@ static int vfio_iommu_type1_dma_rw_chunk(struct vfio_iommu *iommu,* size */ bitmap_set (dma->bitmap, offset >> pgshift, - *copied >> pgshift); + ((offset + *copied -1 ) >> pgshift) - + (offset >> pgshift) +1 ); } }else *copied = copy_from_user(data, (void __user *)vaddr,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 441/633 clk: qcom: gcc-sdm660: Fix wrong parent_map
In reply to Greg Kroah-HartmanFrom: Konrad Dybcio <[email protected]>
[ Upstream commit d46e5a39f9be9288f1ce2170c4c7f8098f4e7f68 ]
This was likely overlooked while porting the driver upstream.
--- drivers/clk/qcom/gcc-sdm660.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/gcc-sdm660.c +1 -1
@@ -666,7 +666,7 @@ static struct clk_rcg2 hmss_rbcpr_clk_src = { .cmd_rcgr = 0x48044, .mnd_width = 0, .hid_width = 5, - .parent_map = gcc_parent_map_xo_gpll0_gpll0_early_div, + .parent_map = gcc_parent_map_xo_gpll0, .freq_tbl = ftbl_hmss_rbcpr_clk_src, .clkr.hw.init = &(struct clk_init_data ){ .name ="hmss_rbcpr_clk_src" ,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 442/633 clk: keystone: sci-clk: fix parsing assigned-clock data during probe
In reply to Greg Kroah-HartmanFrom: Tero Kristo <[email protected]>
[ Upstream commit 2f05cced7307489faab873367fb20cd212e1d890 ]
The DT clock probe loop incorrectly terminates after processing "clocks" only, fix this by re-starting the loop when all entries for current DT property have been parsed.
--- drivers/clk/keystone/sci-clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/keystone/sci-clk.c +1 -1
@@ -522,7 +522,7 @@ static int ti_sci_scan_clocks_from_dt(struct sci_clk_provider *provider) np =of_find_node_with_property (np, *clk_name);if (!np) { clk_name++; -break ; +continue ; }if (!of_device_is_available (np))
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 443/633 pwm: rockchip: Keep enabled PWMs running while probing
In reply to Greg Kroah-HartmanFrom: Simon South <[email protected]>
[ Upstream commit 457f74abbed060a0395f75ab5297f2d76cada516 ]
Following commit cfc4c189bc70 ("pwm: Read initial hardware state at request time") the Rockchip PWM driver can no longer assume a device's pwm_state structure has been populated after a call to pwmchip_add(). Consequently, the test in rockchip_pwm_probe() intended to prevent the driver from stopping PWM devices already enabled by the bootloader no longer functions reliably and this can lead to the kernel hanging during startup, particularly on devices like the Pinebook Pro that use a PWM-controlled backlight for their display.
Avoid this by querying the device directly at probe time to determine whether or not it is enabled.
--- drivers/pwm/pwm-rockchip.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/pwm/pwm-rockchip.c +4 -1
@@ -288,6 +288,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)const struct of_device_id *id;struct rockchip_pwm_chip *pc;struct resource *r; +u32 enable_conf, ctrl;int ret, count; id =of_match_device (rockchip_pwm_dt_ids, &pdev->dev);
@@ -362,7 +363,9 @@ static int rockchip_pwm_probe(struct platform_device *pdev) }/* Keep the PWM clk enabled if the PWM appears to be up and running. */ -if (!pwm_is_enabled (pc->chip.pwms)) + enable_conf = pc->data->enable_conf; + ctrl =readl_relaxed (pc->base + pc->data->regs.ctrl); +if ((ctrl & enable_conf) != enable_conf)clk_disable (pc->clk);return 0 ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 444/633 pwm: img: Fix null pointer access in probe
In reply to Greg Kroah-HartmanFrom: Hauke Mehrtens <[email protected]>
[ Upstream commit b39c0615d0667b3a6f2f5c4bf99ffadf3b518bb1 ]
dev_get_drvdata() is called in img_pwm_runtime_resume() before the driver data is set.
When pm_runtime_enabled() returns false in img_pwm_probe() it calls img_pwm_runtime_resume() which results in a null pointer access.
This patch fixes the problem by setting the driver data earlier in the img_pwm_probe() function.
This crash was seen when booting the Imagination Technologies Creator Ci40 (Marduk) with kernel 5.4 in OpenWrt.
--- drivers/pwm/pwm-img.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/pwm/pwm-img.c +2 -1
@@ -277,6 +277,8 @@ static int img_pwm_probe(struct platform_device *pdev)return PTR_ERR (pwm->pwm_clk); } +platform_set_drvdata (pdev, pwm); +pm_runtime_set_autosuspend_delay (&pdev->dev,IMG_PWM_PM_TIMEOUT );pm_runtime_use_autosuspend (&pdev->dev);pm_runtime_enable (&pdev->dev);
@@ -313,7 +315,6 @@ static int img_pwm_probe(struct platform_device *pdev) goto err_suspend; } -platform_set_drvdata (pdev, pwm);return 0 ; err_suspend:
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 445/633 remoteproc/mediatek: fix null pointer dereference on null scp pointer
In reply to Greg Kroah-HartmanFrom: Colin Ian King <[email protected]>
[ Upstream commit 434ac4d51407ce3764a6ae96a89d90b8ae2826fb ]
Currently when pointer scp is null a dev_err is being called that references the pointer which is the very thing we are trying to avoid doing. Remove the extraneous error message to avoid this issue.
Addresses-Coverity: ("Dereference after null check")
--- drivers/remoteproc/mtk_scp_ipi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/remoteproc/mtk_scp_ipi.c +1 -3
@@ -30,10 +30,8 @@ int scp_ipi_register(struct mtk_scp *scp, scp_ipi_handler_t handler, void *priv) { -if (!scp) { -dev_err (scp->dev,"scp device is not ready\n" ); +if (!scp)return -EPROBE_DEFER ; - }if (WARN_ON (id >=SCP_IPI_MAX ) ||WARN_ON (handler ==NULL ))return -EINVAL ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 446/633 PCI: hv: Fix hibernation in case interrupts are not re-created
In reply to Greg Kroah-HartmanFrom: Dexuan Cui <[email protected]>
[ Upstream commit 915cff7f38c5e4d47f187f8049245afc2cb3e503 ]
pci_restore_msi_state() directly writes the MSI/MSI-X related registers via MMIO. On a physical machine, this works perfectly; for a Linux VM running on a hypervisor, which typically enables IOMMU interrupt remapping, the hypervisor usually should trap and emulate the MMIO accesses in order to re-create the necessary interrupt remapping table entries in the IOMMU, otherwise the interrupts can not work in the VM after hibernation.
Hyper-V is different from other hypervisors in that it does not trap and emulate the MMIO accesses, and instead it uses a para-virtualized method, which requires the VM to call hv_compose_msi_msg() to notify the hypervisor of the info that would be passed to the hypervisor in the case of the trap-and-emulate method. This is not an issue to a lot of PCI device drivers, which destroy and re-create the interrupts across hibernation, so hv_compose_msi_msg() is called automatically. However, some PCI device drivers (e.g. the in-tree GPU driver nouveau and the out-of-tree Nvidia proprietary GPU driver) do not destroy and re-create MSI/MSI-X interrupts across hibernation, so hv_pci_resume() has to call hv_compose_msi_msg(), otherwise the PCI device drivers can no longer receive interrupts after the VM resumes from hibernation.
Hyper-V is also different in that chip->irq_unmask() may fail in a Linux VM running on Hyper-V (on a physical machine, chip->irq_unmask() can not fail because unmasking an MSI/MSI-X register just means an MMIO write): during hibernation, when a CPU is offlined, the kernel tries to move the interrupt to the remaining CPUs that haven't been offlined yet. In this case, hv_irq_unmask() -> hv_do_hypercall() always fails because the vmbus channel has been closed: here the early "return" in hv_irq_unmask() means the pci_msi_unmask_irq() is not called, i.e. the desc->masked remains "true", so later after hibernation, the MSI interrupt always remains masked, which is incorrect. Refer to cpu_disable_common() -> fixup_irqs() -> irq_migrate_all_off_this_cpu() -> migrate_one_irq():
static bool migrate_one_irq(struct irq_desc *desc) {
...
if (maskchip && chip->irq_mask)
chip->irq_mask(d);
...
err = irq_do_set_affinity(d, affinity, false);
...
if (maskchip && chip->irq_unmask)
chip->irq_unmask(d);Fix the issue by calling pci_msi_unmask_irq() unconditionally in hv_irq_unmask(). Also suppress the error message for hibernation because the hypercall failure during hibernation does not matter (at this time all the devices have been frozen). Note: the correct affinity info is still updated into the irqdata data structure in migrate_one_irq() -> irq_do_set_affinity() -> hv_set_affinity(), so later when the VM resumes, hv_pci_restore_msi_state() is able to correctly restore the interrupt with the correct affinity.
--- drivers/pci/controller/pci-hyperv.c | 50 +++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-)
drivers/pci/controller/pci-hyperv.c +47 -3
@@ -1275,11 +1275,25 @@ static void hv_irq_unmask(struct irq_data *data) exit_unlock:spin_unlock_irqrestore (&hbus->retarget_msi_interrupt_lock, flags); -if (res) { +/* +* During hibernation, when a CPU is offlined, the kernel tries +* to move the interrupt to the remaining CPUs that haven't +* been offlined yet. In this case, the below hv_do_hypercall() +* always fails since the vmbus channel has been closed: +* refer to cpu_disable_common() -> fixup_irqs() -> +* irq_migrate_all_off_this_cpu() -> migrate_one_irq(). +* +* Suppress the error message for hibernation because the failure +* during hibernation does not matter (at this time all the devices +* have been frozen). Note: the correct affinity info is still updated +* into the irqdata data structure in migrate_one_irq() -> +* irq_do_set_affinity() -> hv_set_affinity(), so later when the VM +* resumes, hv_pci_restore_msi_state() is able to correctly restore +* the interrupt with the correct affinity. +*/ +if (res && hbus->state != hv_pcibus_removing)dev_err (&hbus->hdev->device,"%s() failed: %#llx" , __func__, res); -return ; - }pci_msi_unmask_irq (data); }
@@ -3368,6 +3382,34 @@ static int hv_pci_suspend(struct hv_device *hdev)return 0 ; } +static int hv_pci_restore_msi_msg (struct pci_dev *pdev,void *arg) +{ +struct msi_desc *entry; +struct irq_data *irq_data; + +for_each_pci_msi_entry (entry, pdev) { + irq_data =irq_get_irq_data (entry->irq); +if (WARN_ON_ONCE (!irq_data)) +return -EINVAL ; + +hv_compose_msi_msg (irq_data, &entry->msg); + } + +return 0 ; +} + +/* +* Upon resume, pci_restore_msi_state() -> ... -> __pci_write_msi_msg() +* directly writes the MSI/MSI-X registers via MMIO, but since Hyper-V +* doesn't trap and emulate the MMIO accesses, here hv_compose_msi_msg() +* must be used to ask Hyper-V to re-create the IOMMU Interrupt Remapping +* Table entries. +*/ +static void hv_pci_restore_msi_state (struct hv_pcibus_device *hbus) +{ +pci_walk_bus (hbus->pci_bus, hv_pci_restore_msi_msg,NULL ); +} +static int hv_pci_resume (struct hv_device *hdev) {struct hv_pcibus_device *hbus =hv_get_drvdata (hdev);
@@ -3401,6 +3443,8 @@ static int hv_pci_resume(struct hv_device *hdev)prepopulate_bars (hbus); +hv_pci_restore_msi_state (hbus); + hbus->state = hv_pcibus_installed;return 0 ; out:
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 447/633 clk: rockchip: Initialize hw to error to avoid undefined behavior
In reply to Greg Kroah-HartmanFrom: Stephen Boyd <[email protected]>
[ Upstream commit b608f11d49ec671739604cc763248d8e8fadbbeb ]
We can get down to this return value from ERR_CAST() without initializing hw. Set it to -ENOMEM so that we always return something sane.
Fixes the following smatch warning:
drivers/clk/rockchip/clk-half-divider.c:228 rockchip_clk_register_halfdiv() error: uninitialized symbol 'hw'. drivers/clk/rockchip/clk-half-divider.c:228 rockchip_clk_register_halfdiv() warn: passing zero to 'ERR_CAST'
--- drivers/clk/rockchip/clk-half-divider.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/rockchip/clk-half-divider.c +1 -1
@@ -166,7 +166,7 @@ struct clk *rockchip_clk_register_halfdiv(const char *name,unsigned long flags, spinlock_t *lock) { - struct clk *clk; + struct clk *clk = ERR_PTR(-ENOMEM);struct clk_mux *mux =NULL ;struct clk_gate *gate =NULL ;struct clk_divider *div =NULL ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 448/633 clk: mediatek: add UART0 clock support
In reply to Greg Kroah-HartmanFrom: Hanks Chen <[email protected]>
[ Upstream commit 804a892456b73604b7ecfb1b00a96a29f3d2aedf ]
Add MT6779 UART0 clock support.
--- drivers/clk/mediatek/clk-mt6779.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/clk/mediatek/clk-mt6779.c +2 -0
@@ -919,6 +919,8 @@ static const struct mtk_gate infra_clks[] = { "pwm_sel", 19),GATE_INFRA0 (CLK_INFRA_PWM ,"infra_pwm" ,"pwm_sel" ,21 ), +GATE_INFRA0 (CLK_INFRA_UART0 ,"infra_uart0" , +"uart_sel" ,22 ),GATE_INFRA0 (CLK_INFRA_UART1 ,"infra_uart1" ,"uart_sel" ,23 ), GATE_INFRA0(CLK_INFRA_UART2, "infra_uart2",
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 449/633 module: statically initialize init section freeing data
In reply to Greg Kroah-HartmanFrom: Daniel Jordan <[email protected]>
[ Upstream commit fdf09ab887829cd1b671e45d9549f8ec1ffda0fa ]
Corentin hit the following workqueue warning when running with CRYPTO_MANAGER_EXTRA_TESTS:
WARNING: CPU: 2 PID: 147 at kernel/workqueue.c:1473 __queue_work+0x3b8/0x3d0
Modules linked in: ghash_generic
CPU: 2 PID: 147 Comm: modprobe Not tainted
5.6.0-rc1-next-20200214-00068-g166c9264f0b1-dirty #545
Hardware name: Pine H64 model A (DT)
pc : __queue_work+0x3b8/0x3d0
Call trace:
__queue_work+0x3b8/0x3d0
queue_work_on+0x6c/0x90
do_init_module+0x188/0x1f0
load_module+0x1d00/0x22b0I wasn't able to reproduce on x86 or rpi 3b+.
This is
WARN_ON(!list_empty(&work->entry))
from __queue_work(), and it happens because the init_free_wq work item isn't initialized in time for a crypto test that requests the gcm module. Some crypto tests were recently moved earlier in boot as explained in commit c4741b230597 ("crypto: run initcalls for generic implementations earlier"), which went into mainline less than two weeks before the Fixes commit.
Avoid the warning by statically initializing init_free_wq and the corresponding llist.
Tested-on: sun50i-h6-pine-h64
Tested-on: imx8mn-ddr4-evk
Tested-on: sun50i-a64-bananapi-m64
--- kernel/module.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-)
kernel/module.c +3 -10
@@ -91,8 +91,9 @@ EXPORT_SYMBOL_GPL(module_mutex);static LIST_HEAD (modules);/* Work queue for freeing init sections in success case */ -static struct work_struct init_free_wq; -static struct llist_head init_free_list; +static void do_free_init (struct work_struct *w); +static DECLARE_WORK(init_free_wq, do_free_init); +static LLIST_HEAD (init_free_list);#ifdef CONFIG_MODULES_TREE_LOOKUP
@@ -3551,14 +3552,6 @@ static void do_free_init(struct work_struct *w) } } -static int __init modules_wq_init (void ) -{ -INIT_WORK (&init_free_wq, do_free_init); -init_llist_head (&init_free_list); -return 0 ; -} -module_init (modules_wq_init); -/* * This is where the real work happens. *
Signature · 1 line
2.25.1