Since being able to immediately react to SIGKILL is good, introduce killable version of hci_dev_lock(). Since there are 270+ hci_dev_lock() callers, this patch updates only hci_debugfs.c part where blindly aborting operation would be acceptable. Although hci_dev_lock_killable() is currently an alias of mutex_lock_killable() which returns either 0 or -EINTR, this patch explicitly receives return value of hci_dev_lock_killable() using a local variable in order to make it possible to add race detection into hci_dev_lock_killable(), and e.g. return 0 without doing anything when a race was detected. Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx> --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_debugfs.c | 221 ++++++++++++++++++++++++------- 2 files changed, 171 insertions(+), 51 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d9e55682b908..f8d0e57407e7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1208,6 +1208,7 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d) } #define hci_dev_lock(d) mutex_lock(&d->lock) +#define hci_dev_lock_killable(d) mutex_lock_killable(&d->lock) #define hci_dev_unlock(d) mutex_unlock(&d->lock) #define to_hci_dev(d) container_of(d, struct hci_dev, dev) diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index 841393389f7b..6a5801d90126 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c @@ -77,8 +77,10 @@ static const struct file_operations __name ## _fops = { \ static int __name ## _show(struct seq_file *f, void *ptr) \ { \ struct hci_dev *hdev = f->private; \ + const int err = hci_dev_lock_killable(hdev); \ \ - hci_dev_lock(hdev); \ + if (err) \ + return err; \ seq_printf(f, "%s\n", hdev->__field ? : ""); \ hci_dev_unlock(hdev); \ \ @@ -91,8 +93,10 @@ static int features_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; u8 p; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) seq_printf(f, "%2u: %8ph\n", p, hdev->features[p]); if (lmp_le_capable(hdev)) @@ -107,8 +111,10 @@ DEFINE_SHOW_ATTRIBUTE(features); static int device_id_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; seq_printf(f, "%4.4x:%4.4x:%4.4x:%4.4x\n", hdev->devid_source, hdev->devid_vendor, hdev->devid_product, hdev->devid_version); hci_dev_unlock(hdev); @@ -123,8 +129,10 @@ static int device_list_show(struct seq_file *f, void *ptr) struct hci_dev *hdev = f->private; struct hci_conn_params *p; struct bdaddr_list *b; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; list_for_each_entry(b, &hdev->accept_list, list) seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); list_for_each_entry(p, &hdev->le_conn_params, list) { @@ -142,8 +150,10 @@ static int blacklist_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; struct bdaddr_list *b; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; list_for_each_entry(b, &hdev->reject_list, list) seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); hci_dev_unlock(hdev); @@ -172,8 +182,10 @@ static int uuids_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; struct bt_uuid *uuid; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; list_for_each_entry(uuid, &hdev->uuids, list) { u8 i, val[16]; @@ -197,8 +209,10 @@ static int remote_oob_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; struct oob_data *data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; list_for_each_entry(data, &hdev->remote_oob_data, list) { seq_printf(f, "%pMR (type %u) %u %*phN %*phN %*phN %*phN\n", &data->bdaddr, data->bdaddr_type, data->present, @@ -215,11 +229,14 @@ DEFINE_SHOW_ATTRIBUTE(remote_oob); static int conn_info_min_age_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val == 0 || val > hdev->conn_info_max_age) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->conn_info_min_age = val; hci_dev_unlock(hdev); @@ -229,8 +246,10 @@ static int conn_info_min_age_set(void *data, u64 val) static int conn_info_min_age_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->conn_info_min_age; hci_dev_unlock(hdev); @@ -243,11 +262,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(conn_info_min_age_fops, conn_info_min_age_get, static int conn_info_max_age_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val == 0 || val < hdev->conn_info_min_age) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->conn_info_max_age = val; hci_dev_unlock(hdev); @@ -257,8 +279,10 @@ static int conn_info_max_age_set(void *data, u64 val) static int conn_info_max_age_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->conn_info_max_age; hci_dev_unlock(hdev); @@ -357,8 +381,10 @@ static int inquiry_cache_show(struct seq_file *f, void *p) struct hci_dev *hdev = f->private; struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; list_for_each_entry(e, &cache->all, all) { struct inquiry_data *data = &e->data; @@ -397,8 +423,10 @@ DEFINE_SHOW_ATTRIBUTE(link_keys); static int dev_class_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; seq_printf(f, "0x%.2x%.2x%.2x\n", hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]); hci_dev_unlock(hdev); @@ -411,8 +439,10 @@ DEFINE_SHOW_ATTRIBUTE(dev_class); static int voice_setting_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->voice_setting; hci_dev_unlock(hdev); @@ -443,8 +473,10 @@ static const struct file_operations ssp_debug_mode_fops = { static int auto_accept_delay_set(void *data, u64 val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; hdev->auto_accept_delay = val; hci_dev_unlock(hdev); @@ -454,11 +486,14 @@ static int auto_accept_delay_set(void *data, u64 val) static int min_encrypt_key_size_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val < 1 || val > 16) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->min_enc_key_size = val; hci_dev_unlock(hdev); @@ -468,8 +503,10 @@ static int min_encrypt_key_size_set(void *data, u64 val) static int min_encrypt_key_size_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->min_enc_key_size; hci_dev_unlock(hdev); @@ -483,8 +520,10 @@ DEFINE_DEBUGFS_ATTRIBUTE(min_encrypt_key_size_fops, static int auto_accept_delay_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->auto_accept_delay; hci_dev_unlock(hdev); @@ -536,11 +575,14 @@ static const struct file_operations force_bredr_smp_fops = { static int idle_timeout_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val != 0 && (val < 500 || val > 3600000)) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->idle_timeout = val; hci_dev_unlock(hdev); @@ -550,8 +592,10 @@ static int idle_timeout_set(void *data, u64 val) static int idle_timeout_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->idle_timeout; hci_dev_unlock(hdev); @@ -564,11 +608,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(idle_timeout_fops, idle_timeout_get, static int sniff_min_interval_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val == 0 || val % 2 || val > hdev->sniff_max_interval) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->sniff_min_interval = val; hci_dev_unlock(hdev); @@ -578,8 +625,10 @@ static int sniff_min_interval_set(void *data, u64 val) static int sniff_min_interval_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->sniff_min_interval; hci_dev_unlock(hdev); @@ -592,11 +641,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(sniff_min_interval_fops, sniff_min_interval_get, static int sniff_max_interval_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val == 0 || val % 2 || val < hdev->sniff_min_interval) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->sniff_max_interval = val; hci_dev_unlock(hdev); @@ -606,8 +658,10 @@ static int sniff_max_interval_set(void *data, u64 val) static int sniff_max_interval_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->sniff_max_interval; hci_dev_unlock(hdev); @@ -663,8 +717,10 @@ static int identity_show(struct seq_file *f, void *p) struct hci_dev *hdev = f->private; bdaddr_t addr; u8 addr_type; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; hci_copy_identity_address(hdev, &addr, &addr_type); @@ -681,6 +737,7 @@ DEFINE_SHOW_ATTRIBUTE(identity); static int rpa_timeout_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; /* Require the RPA timeout to be at least 30 seconds and at most * 24 hours. @@ -688,7 +745,9 @@ static int rpa_timeout_set(void *data, u64 val) if (val < 30 || val > (60 * 60 * 24)) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->rpa_timeout = val; hci_dev_unlock(hdev); @@ -698,8 +757,10 @@ static int rpa_timeout_set(void *data, u64 val) static int rpa_timeout_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->rpa_timeout; hci_dev_unlock(hdev); @@ -712,8 +773,10 @@ DEFINE_DEBUGFS_ATTRIBUTE(rpa_timeout_fops, rpa_timeout_get, static int random_address_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; seq_printf(f, "%pMR\n", &hdev->random_addr); hci_dev_unlock(hdev); @@ -725,8 +788,10 @@ DEFINE_SHOW_ATTRIBUTE(random_address); static int static_address_show(struct seq_file *f, void *p) { struct hci_dev *hdev = f->private; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; seq_printf(f, "%pMR\n", &hdev->static_addr); hci_dev_unlock(hdev); @@ -782,8 +847,10 @@ static int white_list_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; struct bdaddr_list *b; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; list_for_each_entry(b, &hdev->le_accept_list, list) seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); hci_dev_unlock(hdev); @@ -797,8 +864,10 @@ static int resolv_list_show(struct seq_file *f, void *ptr) { struct hci_dev *hdev = f->private; struct bdaddr_list *b; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; list_for_each_entry(b, &hdev->le_resolv_list, list) seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type); hci_dev_unlock(hdev); @@ -847,11 +916,14 @@ DEFINE_SHOW_ATTRIBUTE(long_term_keys); static int conn_min_interval_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val < 0x0006 || val > 0x0c80 || val > hdev->le_conn_max_interval) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_conn_min_interval = val; hci_dev_unlock(hdev); @@ -861,8 +933,10 @@ static int conn_min_interval_set(void *data, u64 val) static int conn_min_interval_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_conn_min_interval; hci_dev_unlock(hdev); @@ -875,11 +949,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(conn_min_interval_fops, conn_min_interval_get, static int conn_max_interval_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val < 0x0006 || val > 0x0c80 || val < hdev->le_conn_min_interval) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_conn_max_interval = val; hci_dev_unlock(hdev); @@ -889,8 +966,10 @@ static int conn_max_interval_set(void *data, u64 val) static int conn_max_interval_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_conn_max_interval; hci_dev_unlock(hdev); @@ -903,11 +982,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get, static int conn_latency_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val > 0x01f3) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_conn_latency = val; hci_dev_unlock(hdev); @@ -917,8 +999,10 @@ static int conn_latency_set(void *data, u64 val) static int conn_latency_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_conn_latency; hci_dev_unlock(hdev); @@ -931,11 +1015,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(conn_latency_fops, conn_latency_get, static int supervision_timeout_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val < 0x000a || val > 0x0c80) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_supv_timeout = val; hci_dev_unlock(hdev); @@ -945,8 +1032,10 @@ static int supervision_timeout_set(void *data, u64 val) static int supervision_timeout_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_supv_timeout; hci_dev_unlock(hdev); @@ -959,11 +1048,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(supervision_timeout_fops, supervision_timeout_get, static int adv_channel_map_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val < 0x01 || val > 0x07) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_adv_channel_map = val; hci_dev_unlock(hdev); @@ -973,8 +1065,10 @@ static int adv_channel_map_set(void *data, u64 val) static int adv_channel_map_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_adv_channel_map; hci_dev_unlock(hdev); @@ -987,11 +1081,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get, static int adv_min_interval_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_adv_min_interval = val; hci_dev_unlock(hdev); @@ -1001,8 +1098,10 @@ static int adv_min_interval_set(void *data, u64 val) static int adv_min_interval_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_adv_min_interval; hci_dev_unlock(hdev); @@ -1015,11 +1114,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get, static int adv_max_interval_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_adv_max_interval = val; hci_dev_unlock(hdev); @@ -1029,8 +1131,10 @@ static int adv_max_interval_set(void *data, u64 val) static int adv_max_interval_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_adv_max_interval; hci_dev_unlock(hdev); @@ -1043,11 +1147,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, static int min_key_size_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val > hdev->le_max_key_size || val < SMP_MIN_ENC_KEY_SIZE) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_min_key_size = val; hci_dev_unlock(hdev); @@ -1057,8 +1164,10 @@ static int min_key_size_set(void *data, u64 val) static int min_key_size_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_min_key_size; hci_dev_unlock(hdev); @@ -1071,11 +1180,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(min_key_size_fops, min_key_size_get, static int max_key_size_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val > SMP_MAX_ENC_KEY_SIZE || val < hdev->le_min_key_size) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->le_max_key_size = val; hci_dev_unlock(hdev); @@ -1085,8 +1197,10 @@ static int max_key_size_set(void *data, u64 val) static int max_key_size_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->le_max_key_size; hci_dev_unlock(hdev); @@ -1099,11 +1213,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(max_key_size_fops, max_key_size_get, static int auth_payload_timeout_set(void *data, u64 val) { struct hci_dev *hdev = data; + int err; if (val < 0x0001 || val > 0xffff) return -EINVAL; - hci_dev_lock(hdev); + err = hci_dev_lock_killable(hdev); + if (err) + return err; hdev->auth_payload_timeout = val; hci_dev_unlock(hdev); @@ -1113,8 +1230,10 @@ static int auth_payload_timeout_set(void *data, u64 val) static int auth_payload_timeout_get(void *data, u64 *val) { struct hci_dev *hdev = data; + const int err = hci_dev_lock_killable(hdev); - hci_dev_lock(hdev); + if (err) + return err; *val = hdev->auth_payload_timeout; hci_dev_unlock(hdev); -- 2.18.4