You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking updates from Ingo Molnar:
"The main changes in this cycle were:
- Implement wraparound-safe refcount_t and kref_t types based on
generic atomic primitives (Peter Zijlstra)
- Improve and fix the ww_mutex code (Nicolai Hähnle)
- Add self-tests to the ww_mutex code (Chris Wilson)
- Optimize percpu-rwsems with the 'rcuwait' mechanism (Davidlohr
Bueso)
- Micro-optimize the current-task logic all around the core kernel
(Davidlohr Bueso)
- Tidy up after recent optimizations: remove stale code and APIs,
clean up the code (Waiman Long)
- ... plus misc fixes, updates and cleanups"
* 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (50 commits)
fork: Fix task_struct alignment
locking/spinlock/debug: Remove spinlock lockup detection code
lockdep: Fix incorrect condition to print bug msgs for MAX_LOCKDEP_CHAIN_HLOCKS
lkdtm: Convert to refcount_t testing
kref: Implement 'struct kref' using refcount_t
refcount_t: Introduce a special purpose refcount type
sched/wake_q: Clarify queue reinit comment
sched/wait, rcuwait: Fix typo in comment
locking/mutex: Fix lockdep_assert_held() fail
locking/rtmutex: Flip unlikely() branch to likely() in __rt_mutex_slowlock()
locking/rwsem: Reinit wake_q after use
locking/rwsem: Remove unnecessary atomic_long_t casts
jump_labels: Move header guard #endif down where it belongs
locking/atomic, kref: Implement kref_put_lock()
locking/ww_mutex: Turn off __must_check for now
locking/atomic, kref: Avoid more abuse
locking/atomic, kref: Use kref_get_unless_zero() more
locking/atomic, kref: Kill kref_sub()
locking/atomic, kref: Add kref_read()
locking/atomic, kref: Add KREF_INIT()
...
This commit is contained in:
@@ -309,11 +309,15 @@ Design:
|
||||
normal mutex locks, which are far more common. As such there is only a small
|
||||
increase in code size if wait/wound mutexes are not used.
|
||||
|
||||
We maintain the following invariants for the wait list:
|
||||
(1) Waiters with an acquire context are sorted by stamp order; waiters
|
||||
without an acquire context are interspersed in FIFO order.
|
||||
(2) Among waiters with contexts, only the first one can have other locks
|
||||
acquired already (ctx->acquired > 0). Note that this waiter may come
|
||||
after other waiters without contexts in the list.
|
||||
|
||||
In general, not much contention is expected. The locks are typically used to
|
||||
serialize access to resources for devices. The only way to make wakeups
|
||||
smarter would be at the cost of adding a field to struct mutex_waiter. This
|
||||
would add overhead to all cases where normal mutexes are used, and
|
||||
ww_mutexes are generally less performance sensitive.
|
||||
serialize access to resources for devices.
|
||||
|
||||
Lockdep:
|
||||
Special care has been taken to warn for as many cases of api abuse
|
||||
|
||||
@@ -76,7 +76,7 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
|
||||
add_sigio_fd(random_fd);
|
||||
|
||||
add_wait_queue(&host_read_wait, &wait);
|
||||
set_task_state(current, TASK_INTERRUPTIBLE);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
schedule();
|
||||
remove_wait_queue(&host_read_wait, &wait);
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
/* How long a lock should spin before we consider blocking */
|
||||
#define SPIN_THRESHOLD (1 << 15)
|
||||
|
||||
extern struct static_key paravirt_ticketlocks_enabled;
|
||||
static __always_inline bool static_key_false(struct static_key *key);
|
||||
|
||||
#include <asm/qspinlock.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -32,8 +32,7 @@ static void bug_at(unsigned char *ip, int line)
|
||||
* Something went wrong. Crash the box, as something could be
|
||||
* corrupting the kernel.
|
||||
*/
|
||||
pr_warning("Unexpected op at %pS [%p] (%02x %02x %02x %02x %02x) %s:%d\n",
|
||||
ip, ip, ip[0], ip[1], ip[2], ip[3], ip[4], __FILE__, line);
|
||||
pr_crit("jump_label: Fatal kernel bug, unexpected op at %pS [%p] (%5ph) %d\n", ip, ip, ip, line);
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
||||
@@ -620,18 +620,4 @@ void __init kvm_spinlock_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
static __init int kvm_spinlock_init_jump(void)
|
||||
{
|
||||
if (!kvm_para_available())
|
||||
return 0;
|
||||
if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
|
||||
return 0;
|
||||
|
||||
static_key_slow_inc(¶virt_ticketlocks_enabled);
|
||||
printk(KERN_INFO "KVM setup paravirtual spinlock\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_initcall(kvm_spinlock_init_jump);
|
||||
|
||||
#endif /* CONFIG_PARAVIRT_SPINLOCKS */
|
||||
|
||||
@@ -42,6 +42,3 @@ struct pv_lock_ops pv_lock_ops = {
|
||||
#endif /* SMP */
|
||||
};
|
||||
EXPORT_SYMBOL(pv_lock_ops);
|
||||
|
||||
struct static_key paravirt_ticketlocks_enabled = STATIC_KEY_INIT_FALSE;
|
||||
EXPORT_SYMBOL(paravirt_ticketlocks_enabled);
|
||||
|
||||
@@ -141,25 +141,6 @@ void __init xen_init_spinlocks(void)
|
||||
pv_lock_ops.vcpu_is_preempted = PV_CALLEE_SAVE(xen_vcpu_stolen);
|
||||
}
|
||||
|
||||
/*
|
||||
* While the jump_label init code needs to happend _after_ the jump labels are
|
||||
* enabled and before SMP is started. Hence we use pre-SMP initcall level
|
||||
* init. We cannot do it in xen_init_spinlocks as that is done before
|
||||
* jump labels are activated.
|
||||
*/
|
||||
static __init int xen_init_spinlocks_jump(void)
|
||||
{
|
||||
if (!xen_pvspin)
|
||||
return 0;
|
||||
|
||||
if (!xen_domain())
|
||||
return 0;
|
||||
|
||||
static_key_slow_inc(¶virt_ticketlocks_enabled);
|
||||
return 0;
|
||||
}
|
||||
early_initcall(xen_init_spinlocks_jump);
|
||||
|
||||
static __init int xen_parse_nopvspin(char *arg)
|
||||
{
|
||||
xen_pvspin = false;
|
||||
|
||||
@@ -1070,7 +1070,7 @@ static int bm_rw(struct drbd_device *device, const unsigned int flags, unsigned
|
||||
.done = 0,
|
||||
.flags = flags,
|
||||
.error = 0,
|
||||
.kref = { ATOMIC_INIT(2) },
|
||||
.kref = KREF_INIT(2),
|
||||
};
|
||||
|
||||
if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in drbd_bm_aio_ctx_destroy() */
|
||||
|
||||
@@ -2948,7 +2948,6 @@ void drbd_delete_device(struct drbd_device *device)
|
||||
struct drbd_resource *resource = device->resource;
|
||||
struct drbd_connection *connection;
|
||||
struct drbd_peer_device *peer_device;
|
||||
int refs = 3;
|
||||
|
||||
/* move to free_peer_device() */
|
||||
for_each_peer_device(peer_device, device)
|
||||
@@ -2956,13 +2955,15 @@ void drbd_delete_device(struct drbd_device *device)
|
||||
drbd_debugfs_device_cleanup(device);
|
||||
for_each_connection(connection, resource) {
|
||||
idr_remove(&connection->peer_devices, device->vnr);
|
||||
refs++;
|
||||
kref_put(&device->kref, drbd_destroy_device);
|
||||
}
|
||||
idr_remove(&resource->devices, device->vnr);
|
||||
kref_put(&device->kref, drbd_destroy_device);
|
||||
idr_remove(&drbd_devices, device_to_minor(device));
|
||||
kref_put(&device->kref, drbd_destroy_device);
|
||||
del_gendisk(device->vdisk);
|
||||
synchronize_rcu();
|
||||
kref_sub(&device->kref, refs, drbd_destroy_device);
|
||||
kref_put(&device->kref, drbd_destroy_device);
|
||||
}
|
||||
|
||||
static int __init drbd_init(void)
|
||||
|
||||
@@ -421,7 +421,6 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
|
||||
struct drbd_peer_device *peer_device = first_peer_device(device);
|
||||
unsigned s = req->rq_state;
|
||||
int c_put = 0;
|
||||
int k_put = 0;
|
||||
|
||||
if (drbd_suspended(device) && !((s | clear) & RQ_COMPLETION_SUSP))
|
||||
set |= RQ_COMPLETION_SUSP;
|
||||
@@ -437,6 +436,8 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
|
||||
|
||||
/* intent: get references */
|
||||
|
||||
kref_get(&req->kref);
|
||||
|
||||
if (!(s & RQ_LOCAL_PENDING) && (set & RQ_LOCAL_PENDING))
|
||||
atomic_inc(&req->completion_ref);
|
||||
|
||||
@@ -473,15 +474,12 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
|
||||
|
||||
if (!(s & RQ_LOCAL_ABORTED) && (set & RQ_LOCAL_ABORTED)) {
|
||||
D_ASSERT(device, req->rq_state & RQ_LOCAL_PENDING);
|
||||
/* local completion may still come in later,
|
||||
* we need to keep the req object around. */
|
||||
kref_get(&req->kref);
|
||||
++c_put;
|
||||
}
|
||||
|
||||
if ((s & RQ_LOCAL_PENDING) && (clear & RQ_LOCAL_PENDING)) {
|
||||
if (req->rq_state & RQ_LOCAL_ABORTED)
|
||||
++k_put;
|
||||
kref_put(&req->kref, drbd_req_destroy);
|
||||
else
|
||||
++c_put;
|
||||
list_del_init(&req->req_pending_local);
|
||||
@@ -503,7 +501,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
|
||||
if (s & RQ_NET_SENT)
|
||||
atomic_sub(req->i.size >> 9, &device->ap_in_flight);
|
||||
if (s & RQ_EXP_BARR_ACK)
|
||||
++k_put;
|
||||
kref_put(&req->kref, drbd_req_destroy);
|
||||
req->net_done_jif = jiffies;
|
||||
|
||||
/* in ahead/behind mode, or just in case,
|
||||
@@ -516,25 +514,16 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m,
|
||||
|
||||
/* potentially complete and destroy */
|
||||
|
||||
if (k_put || c_put) {
|
||||
/* Completion does it's own kref_put. If we are going to
|
||||
* kref_sub below, we need req to be still around then. */
|
||||
int at_least = k_put + !!c_put;
|
||||
int refcount = atomic_read(&req->kref.refcount);
|
||||
if (refcount < at_least)
|
||||
drbd_err(device,
|
||||
"mod_rq_state: Logic BUG: %x -> %x: refcount = %d, should be >= %d\n",
|
||||
s, req->rq_state, refcount, at_least);
|
||||
}
|
||||
|
||||
/* If we made progress, retry conflicting peer requests, if any. */
|
||||
if (req->i.waiting)
|
||||
wake_up(&device->misc_wait);
|
||||
|
||||
if (c_put)
|
||||
k_put += drbd_req_put_completion_ref(req, m, c_put);
|
||||
if (k_put)
|
||||
kref_sub(&req->kref, k_put, drbd_req_destroy);
|
||||
if (c_put) {
|
||||
if (drbd_req_put_completion_ref(req, m, c_put))
|
||||
kref_put(&req->kref, drbd_req_destroy);
|
||||
} else {
|
||||
kref_put(&req->kref, drbd_req_destroy);
|
||||
}
|
||||
}
|
||||
|
||||
static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req)
|
||||
|
||||
+4
-4
@@ -1535,7 +1535,7 @@ static bool obj_request_overlaps_parent(struct rbd_obj_request *obj_request)
|
||||
static void rbd_obj_request_get(struct rbd_obj_request *obj_request)
|
||||
{
|
||||
dout("%s: obj %p (was %d)\n", __func__, obj_request,
|
||||
atomic_read(&obj_request->kref.refcount));
|
||||
kref_read(&obj_request->kref));
|
||||
kref_get(&obj_request->kref);
|
||||
}
|
||||
|
||||
@@ -1544,14 +1544,14 @@ static void rbd_obj_request_put(struct rbd_obj_request *obj_request)
|
||||
{
|
||||
rbd_assert(obj_request != NULL);
|
||||
dout("%s: obj %p (was %d)\n", __func__, obj_request,
|
||||
atomic_read(&obj_request->kref.refcount));
|
||||
kref_read(&obj_request->kref));
|
||||
kref_put(&obj_request->kref, rbd_obj_request_destroy);
|
||||
}
|
||||
|
||||
static void rbd_img_request_get(struct rbd_img_request *img_request)
|
||||
{
|
||||
dout("%s: img %p (was %d)\n", __func__, img_request,
|
||||
atomic_read(&img_request->kref.refcount));
|
||||
kref_read(&img_request->kref));
|
||||
kref_get(&img_request->kref);
|
||||
}
|
||||
|
||||
@@ -1562,7 +1562,7 @@ static void rbd_img_request_put(struct rbd_img_request *img_request)
|
||||
{
|
||||
rbd_assert(img_request != NULL);
|
||||
dout("%s: img %p (was %d)\n", __func__, img_request,
|
||||
atomic_read(&img_request->kref.refcount));
|
||||
kref_read(&img_request->kref));
|
||||
if (img_request_child_test(img_request))
|
||||
kref_put(&img_request->kref, rbd_parent_request_destroy);
|
||||
else
|
||||
|
||||
@@ -770,7 +770,7 @@ static void virtblk_remove(struct virtio_device *vdev)
|
||||
/* Stop all the virtqueues. */
|
||||
vdev->config->reset(vdev);
|
||||
|
||||
refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount);
|
||||
refc = kref_read(&disk_to_dev(vblk->disk)->kobj.kref);
|
||||
put_disk(vblk->disk);
|
||||
vdev->config->del_vqs(vdev);
|
||||
kfree(vblk->vqs);
|
||||
|
||||
@@ -376,7 +376,7 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj,
|
||||
off = drm_vma_node_start(&obj->vma_node);
|
||||
|
||||
seq_printf(m, "%2d (%2d) %08llx %pad %p %zu",
|
||||
obj->name, obj->refcount.refcount.counter,
|
||||
obj->name, kref_read(&obj->refcount),
|
||||
off, &cma_obj->paddr, cma_obj->vaddr, obj->size);
|
||||
|
||||
seq_printf(m, "\n");
|
||||
|
||||
@@ -118,7 +118,7 @@ static int drm_gem_one_name_info(int id, void *ptr, void *data)
|
||||
seq_printf(m, "%6d %8zd %7d %8d\n",
|
||||
obj->name, obj->size,
|
||||
obj->handle_count,
|
||||
atomic_read(&obj->refcount.refcount));
|
||||
kref_read(&obj->refcount));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ EXPORT_SYMBOL(drm_mode_object_find);
|
||||
void drm_mode_object_unreference(struct drm_mode_object *obj)
|
||||
{
|
||||
if (obj->free_cb) {
|
||||
DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
|
||||
DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
|
||||
kref_put(&obj->refcount, obj->free_cb);
|
||||
}
|
||||
}
|
||||
@@ -176,7 +176,7 @@ EXPORT_SYMBOL(drm_mode_object_unreference);
|
||||
void drm_mode_object_reference(struct drm_mode_object *obj)
|
||||
{
|
||||
if (obj->free_cb) {
|
||||
DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount));
|
||||
DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount));
|
||||
kref_get(&obj->refcount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +486,7 @@ static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
|
||||
|
||||
seq_printf(m, "%08x: %c %2d (%2d) %08lx %p %zd\n",
|
||||
etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I',
|
||||
obj->name, obj->refcount.refcount.counter,
|
||||
obj->name, kref_read(&obj->refcount),
|
||||
off, etnaviv_obj->vaddr, obj->size);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
@@ -256,7 +256,7 @@ extern void drm_gem_object_unreference_unlocked(struct drm_gem_object *);
|
||||
static inline bool
|
||||
i915_gem_object_is_dead(const struct drm_i915_gem_object *obj)
|
||||
{
|
||||
return atomic_read(&obj->base.refcount.refcount) == 0;
|
||||
return kref_read(&obj->base.refcount) == 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
||||
@@ -642,7 +642,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
|
||||
|
||||
seq_printf(m, "%08x: %c %2d (%2d) %08llx %p\t",
|
||||
msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
|
||||
obj->name, obj->refcount.refcount.counter,
|
||||
obj->name, kref_read(&obj->refcount),
|
||||
off, msm_obj->vaddr);
|
||||
|
||||
for (id = 0; id < priv->num_aspaces; id++)
|
||||
|
||||
@@ -527,7 +527,7 @@ static bool nouveau_fence_no_signaling(struct dma_fence *f)
|
||||
* caller should have a reference on the fence,
|
||||
* else fence could get freed here
|
||||
*/
|
||||
WARN_ON(atomic_read(&fence->base.refcount.refcount) <= 1);
|
||||
WARN_ON(kref_read(&fence->base.refcount) <= 1);
|
||||
|
||||
/*
|
||||
* This needs uevents to work correctly, but dma_fence_add_callback relies on
|
||||
|
||||
@@ -1033,7 +1033,7 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
|
||||
off = drm_vma_node_start(&obj->vma_node);
|
||||
|
||||
seq_printf(m, "%08x: %2d (%2d) %08llx %pad (%2d) %p %4d",
|
||||
omap_obj->flags, obj->name, obj->refcount.refcount.counter,
|
||||
omap_obj->flags, obj->name, kref_read(&obj->refcount),
|
||||
off, &omap_obj->paddr, omap_obj->paddr_cnt,
|
||||
omap_obj->vaddr, omap_obj->roll);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user