Skip to content

Commit

Permalink
Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm…
Browse files Browse the repository at this point in the history
…/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()
  ...
  • Loading branch information
torvalds committed Feb 20, 2017
2 parents 828cad8 + 95cb64c commit 42e1b14
Show file tree
Hide file tree
Showing 116 changed files with 1,864 additions and 761 deletions.
12 changes: 8 additions & 4 deletions Documentation/locking/ww-mutex-design.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arch/um/drivers/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 0 additions & 3 deletions arch/x86/include/asm/spinlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

/*
Expand Down
3 changes: 1 addition & 2 deletions arch/x86/kernel/jump_label.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
14 changes: 0 additions & 14 deletions arch/x86/kernel/kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(&paravirt_ticketlocks_enabled);
printk(KERN_INFO "KVM setup paravirtual spinlock\n");

return 0;
}
early_initcall(kvm_spinlock_init_jump);

#endif /* CONFIG_PARAVIRT_SPINLOCKS */
3 changes: 0 additions & 3 deletions arch/x86/kernel/paravirt-spinlocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
19 changes: 0 additions & 19 deletions arch/x86/xen/spinlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(&paravirt_ticketlocks_enabled);
return 0;
}
early_initcall(xen_init_spinlocks_jump);

static __init int xen_parse_nopvspin(char *arg)
{
xen_pvspin = false;
Expand Down
2 changes: 1 addition & 1 deletion drivers/block/drbd/drbd_bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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() */
Expand Down
7 changes: 4 additions & 3 deletions drivers/block/drbd/drbd_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2948,21 +2948,22 @@ 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)
drbd_debugfs_peer_device_cleanup(peer_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)
Expand Down
31 changes: 10 additions & 21 deletions drivers/block/drbd/drbd_req.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions drivers/block/rbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion drivers/block/virtio_blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_gem_cma_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/drm_mode_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/etnaviv/etnaviv_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/i915_gem_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/msm/msm_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++)
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/nouveau/nouveau_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/omapdrm/omap_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading

0 comments on commit 42e1b14

Please sign in to comment.