diff options
| -rw-r--r-- | drivers/nvme/host/core.c | 36 |
1 files changed, 11 insertions, 25 deletions
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index d6ca4598c027..dee8e71baf62 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c | |||
| @@ -3197,40 +3197,28 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl *ctrl, unsigned nn) | |||
| 3197 | nvme_remove_invalid_namespaces(ctrl, nn); | 3197 | nvme_remove_invalid_namespaces(ctrl, nn); |
| 3198 | } | 3198 | } |
| 3199 | 3199 | ||
| 3200 | static bool nvme_scan_changed_ns_log(struct nvme_ctrl *ctrl) | 3200 | static void nvme_clear_changed_ns_log(struct nvme_ctrl *ctrl) |
| 3201 | { | 3201 | { |
| 3202 | size_t log_size = NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32); | 3202 | size_t log_size = NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32); |
| 3203 | __le32 *log; | 3203 | __le32 *log; |
| 3204 | int error, i; | 3204 | int error; |
| 3205 | bool ret = false; | ||
| 3206 | 3205 | ||
| 3207 | log = kzalloc(log_size, GFP_KERNEL); | 3206 | log = kzalloc(log_size, GFP_KERNEL); |
| 3208 | if (!log) | 3207 | if (!log) |
| 3209 | return false; | 3208 | return; |
| 3210 | 3209 | ||
| 3210 | /* | ||
| 3211 | * We need to read the log to clear the AEN, but we don't want to rely | ||
| 3212 | * on it for the changed namespace information as userspace could have | ||
| 3213 | * raced with us in reading the log page, which could cause us to miss | ||
| 3214 | * updates. | ||
| 3215 | */ | ||
| 3211 | error = nvme_get_log(ctrl, NVME_LOG_CHANGED_NS, log, log_size); | 3216 | error = nvme_get_log(ctrl, NVME_LOG_CHANGED_NS, log, log_size); |
| 3212 | if (error) { | 3217 | if (error) |
| 3213 | dev_warn(ctrl->device, | 3218 | dev_warn(ctrl->device, |
| 3214 | "reading changed ns log failed: %d\n", error); | 3219 | "reading changed ns log failed: %d\n", error); |
| 3215 | goto out_free_log; | ||
| 3216 | } | ||
| 3217 | |||
| 3218 | if (log[0] == cpu_to_le32(0xffffffff)) | ||
| 3219 | goto out_free_log; | ||
| 3220 | 3220 | ||
| 3221 | for (i = 0; i < NVME_MAX_CHANGED_NAMESPACES; i++) { | ||
| 3222 | u32 nsid = le32_to_cpu(log[i]); | ||
| 3223 | |||
| 3224 | if (nsid == 0) | ||
| 3225 | break; | ||
| 3226 | dev_info(ctrl->device, "rescanning namespace %d.\n", nsid); | ||
| 3227 | nvme_validate_ns(ctrl, nsid); | ||
| 3228 | } | ||
| 3229 | ret = true; | ||
| 3230 | |||
| 3231 | out_free_log: | ||
| 3232 | kfree(log); | 3221 | kfree(log); |
| 3233 | return ret; | ||
| 3234 | } | 3222 | } |
| 3235 | 3223 | ||
| 3236 | static void nvme_scan_work(struct work_struct *work) | 3224 | static void nvme_scan_work(struct work_struct *work) |
| @@ -3246,9 +3234,8 @@ static void nvme_scan_work(struct work_struct *work) | |||
| 3246 | WARN_ON_ONCE(!ctrl->tagset); | 3234 | WARN_ON_ONCE(!ctrl->tagset); |
| 3247 | 3235 | ||
| 3248 | if (test_and_clear_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events)) { | 3236 | if (test_and_clear_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events)) { |
| 3249 | if (nvme_scan_changed_ns_log(ctrl)) | ||
| 3250 | goto out_sort_namespaces; | ||
| 3251 | dev_info(ctrl->device, "rescanning namespaces.\n"); | 3237 | dev_info(ctrl->device, "rescanning namespaces.\n"); |
| 3238 | nvme_clear_changed_ns_log(ctrl); | ||
| 3252 | } | 3239 | } |
| 3253 | 3240 | ||
| 3254 | if (nvme_identify_ctrl(ctrl, &id)) | 3241 | if (nvme_identify_ctrl(ctrl, &id)) |
| @@ -3263,7 +3250,6 @@ static void nvme_scan_work(struct work_struct *work) | |||
| 3263 | nvme_scan_ns_sequential(ctrl, nn); | 3250 | nvme_scan_ns_sequential(ctrl, nn); |
| 3264 | out_free_id: | 3251 | out_free_id: |
| 3265 | kfree(id); | 3252 | kfree(id); |
| 3266 | out_sort_namespaces: | ||
| 3267 | down_write(&ctrl->namespaces_rwsem); | 3253 | down_write(&ctrl->namespaces_rwsem); |
| 3268 | list_sort(NULL, &ctrl->namespaces, ns_cmp); | 3254 | list_sort(NULL, &ctrl->namespaces, ns_cmp); |
| 3269 | up_write(&ctrl->namespaces_rwsem); | 3255 | up_write(&ctrl->namespaces_rwsem); |
