From f3cdf905c522837e2cdce779a03b4ecf16313c65 Mon Sep 17 00:00:00 2001 From: Sergey Cheremencev Date: Tue, 19 Nov 2019 16:09:14 +0300 Subject: [PATCH] LU-12193 quota: use rw_sem to protect lqs_hash Patch introduces rw semaphore for locking in cfs_hash_lock. It is used to protect lqs_hash instead of rw_lock to avoid sleeping in atomic: BUG: sleeping function called from invalid context at kernel/rwsem.c:51 in_atomic(): 1, irqs_disabled(): 0, pid: 11265, name: mdt00_004 CPU: 0 PID: 11265 Comm: mdt00_004 Kdump: loaded Tainted: P Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 Call Trace: [] dump_stack+0x19/0x1b [] __might_sleep+0xd9/0x100 [] down_write+0x20/0x50 [] qmt_set_with_lqe+0x3a9/0x750 [lquota] [] qmt_entry_iter_cb+0x5e/0xa0 [lquota] [] cfs_hash_for_each_tight+0x10c/0x300 [libcfs] [] cfs_hash_for_each_safe+0x13/0x20 [libcfs] [] qmt_set_with_lqe+0x41f/0x750 [lquota] [] qmt_set.constprop.15+0x89/0x2a0 [lquota] [] qmt_quotactl+0x489/0x560 [lquota] [] mdt_quotactl+0x620/0x770 [mdt] [] tgt_request_handle+0x915/0x15c0 [ptlrpc] [] ptlrpc_server_handle_request+0x259/0xad0 [ptlrpc] [] ptlrpc_main+0xca1/0x2290 [ptlrpc] [] kthread+0xe4/0xf0 [] ret_from_fork_nospec_begin+0x21/0x21 [ 280.258396] BUG: scheduling while atomic: mdt00_004/11265/0x10000003 Change-Id: Id9238f9001c38105fb91d29c47fa34ad35158b40 Signed-off-by: Sergey Cheremencev Reviewed-on: https://review.whamcloud.com/36795 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Alexandr Boyko Reviewed-by: James Simmons Reviewed-by: Alex Zhuravlev Reviewed-by: Oleg Drokin --- libcfs/include/libcfs/libcfs_hash.h | 10 ++++++ libcfs/libcfs/hash.c | 61 ++++++++++++++++++++++++++++++++----- lustre/quota/lquota_entry.c | 6 +++- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/libcfs/include/libcfs/libcfs_hash.h b/libcfs/include/libcfs/libcfs_hash.h index bd3d7d0..b541fe3 100644 --- a/libcfs/include/libcfs/libcfs_hash.h +++ b/libcfs/include/libcfs/libcfs_hash.h @@ -74,6 +74,7 @@ struct cfs_hash_hlist_ops; union cfs_hash_lock { rwlock_t rw; /**< rwlock */ spinlock_t spin; /**< spinlock */ + struct rw_semaphore rw_sem; /**< rwsem */ }; /** @@ -155,6 +156,8 @@ enum cfs_hash_tag { * change on hash table is non-blocking */ CFS_HASH_NBLK_CHANGE = 1 << 13, + /** rw semaphore lock to protect bucket */ + CFS_HASH_RW_SEM_BKTLOCK = 1 << 14, /** NB, we typed hs_flags as __u16, please change it * if you need to extend >=16 flags */ }; @@ -360,6 +363,13 @@ cfs_hash_with_spin_bktlock(struct cfs_hash *hs) } static inline int +cfs_hash_with_rw_sem_bktlock(struct cfs_hash *hs) +{ + /* rw sem lock to protect hash bucket */ + return (hs->hs_flags & CFS_HASH_RW_SEM_BKTLOCK) != 0; +} + +static inline int cfs_hash_with_add_tail(struct cfs_hash *hs) { return (hs->hs_flags & CFS_HASH_ADD_TAIL) != 0; diff --git a/libcfs/libcfs/hash.c b/libcfs/libcfs/hash.c index 3d2127f..9fee65e 100644 --- a/libcfs/libcfs/hash.c +++ b/libcfs/libcfs/hash.c @@ -156,6 +156,26 @@ cfs_hash_rw_unlock(union cfs_hash_lock *lock, int exclusive) write_unlock(&lock->rw); } +static inline void +cfs_hash_rw_sem_lock(union cfs_hash_lock *lock, int exclusive) + __acquires(&lock->rw_sem) +{ + if (!exclusive) + down_read(&lock->rw_sem); + else + down_write(&lock->rw_sem); +} + +static inline void +cfs_hash_rw_sem_unlock(union cfs_hash_lock *lock, int exclusive) + __releases(&lock->rw_sem) +{ + if (!exclusive) + up_read(&lock->rw_sem); + else + up_write(&lock->rw_sem); +} + /** No lock hash */ static struct cfs_hash_lock_ops cfs_hash_nl_lops = { .hs_lock = cfs_hash_nl_lock, @@ -204,6 +224,22 @@ static struct cfs_hash_lock_ops cfs_hash_nr_bkt_rw_lops = { .hs_bkt_unlock = cfs_hash_rw_unlock, }; +/** rw_sem bucket lock, rehash is disabled */ +static struct cfs_hash_lock_ops cfs_hash_nr_bkt_rw_sem_lops = { + .hs_lock = cfs_hash_nl_lock, + .hs_unlock = cfs_hash_nl_unlock, + .hs_bkt_lock = cfs_hash_rw_sem_lock, + .hs_bkt_unlock = cfs_hash_rw_sem_unlock, +}; + +/** rw_sem bucket lock, rehash is enabled */ +static struct cfs_hash_lock_ops cfs_hash_bkt_rw_sem_lops = { + .hs_lock = cfs_hash_rw_sem_lock, + .hs_unlock = cfs_hash_rw_sem_unlock, + .hs_bkt_lock = cfs_hash_rw_sem_lock, + .hs_bkt_unlock = cfs_hash_rw_sem_unlock, +}; + static void cfs_hash_lock_setup(struct cfs_hash *hs) { @@ -215,19 +251,26 @@ cfs_hash_lock_setup(struct cfs_hash *hs) spin_lock_init(&hs->hs_lock.spin); } else if (cfs_hash_with_rehash(hs)) { - rwlock_init(&hs->hs_lock.rw); - - if (cfs_hash_with_rw_bktlock(hs)) - hs->hs_lops = &cfs_hash_bkt_rw_lops; - else if (cfs_hash_with_spin_bktlock(hs)) - hs->hs_lops = &cfs_hash_bkt_spin_lops; - else - LBUG(); + if (cfs_hash_with_rw_sem_bktlock(hs)) { + init_rwsem(&hs->hs_lock.rw_sem); + hs->hs_lops = &cfs_hash_bkt_rw_sem_lops; + } else { + rwlock_init(&hs->hs_lock.rw); + + if (cfs_hash_with_rw_bktlock(hs)) + hs->hs_lops = &cfs_hash_bkt_rw_lops; + else if (cfs_hash_with_spin_bktlock(hs)) + hs->hs_lops = &cfs_hash_bkt_spin_lops; + else + LBUG(); + } } else { if (cfs_hash_with_rw_bktlock(hs)) hs->hs_lops = &cfs_hash_nr_bkt_rw_lops; else if (cfs_hash_with_spin_bktlock(hs)) hs->hs_lops = &cfs_hash_nr_bkt_spin_lops; + else if (cfs_hash_with_rw_sem_bktlock(hs)) + hs->hs_lops = &cfs_hash_nr_bkt_rw_sem_lops; else LBUG(); } @@ -925,6 +968,8 @@ cfs_hash_buckets_realloc(struct cfs_hash *hs, struct cfs_hash_bucket **old_bkts, rwlock_init(&new_bkts[i]->hsb_lock.rw); else if (cfs_hash_with_spin_bktlock(hs)) spin_lock_init(&new_bkts[i]->hsb_lock.spin); + else if (cfs_hash_with_rw_sem_bktlock(hs)) + init_rwsem(&new_bkts[i]->hsb_lock.rw_sem); else LBUG(); /* invalid use-case */ } diff --git a/lustre/quota/lquota_entry.c b/lustre/quota/lquota_entry.c index 3cc8fb2..ee73c16 100644 --- a/lustre/quota/lquota_entry.c +++ b/lustre/quota/lquota_entry.c @@ -228,7 +228,11 @@ struct lquota_site *lquota_site_alloc(const struct lu_env *env, void *parent, HASH_LQE_BKT_BITS), 0, CFS_HASH_MIN_THETA, CFS_HASH_MAX_THETA, &lqe64_hash_ops, - CFS_HASH_DEFAULT|CFS_HASH_BIGNAME); + CFS_HASH_RW_SEM_BKTLOCK | + CFS_HASH_COUNTER | + CFS_HASH_REHASH | + CFS_HASH_BIGNAME); + if (site->lqs_hash == NULL) { OBD_FREE_PTR(site); RETURN(ERR_PTR(-ENOMEM)); -- 1.8.3.1