Skip to content

Commit d0a712c

Browse files
Wenwei0320axboe
authored andcommitted
lightnvm: missing nvm_lock acquire
To avoid race conditions, traverse dev, media manager, and target lists and also register, unregister entries to/from them, should be always under the nvm_lock control. Signed-off-by: Wenwei Tao <[email protected]> Signed-off-by: Matias Bjørling <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 08236c6 commit d0a712c

File tree

1 file changed

+42
-33
lines changed

1 file changed

+42
-33
lines changed

drivers/lightnvm/core.c

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,26 @@ void nvm_unregister_mgr(struct nvmm_type *mt)
123123
}
124124
EXPORT_SYMBOL(nvm_unregister_mgr);
125125

126+
/* register with device with a supported manager */
127+
static int register_mgr(struct nvm_dev *dev)
128+
{
129+
struct nvmm_type *mt;
130+
int ret = 0;
131+
132+
list_for_each_entry(mt, &nvm_mgrs, list) {
133+
ret = mt->register_mgr(dev);
134+
if (ret > 0) {
135+
dev->mt = mt;
136+
break; /* successfully initialized */
137+
}
138+
}
139+
140+
if (!ret)
141+
pr_info("nvm: no compatible nvm manager found.\n");
142+
143+
return ret;
144+
}
145+
126146
static struct nvm_dev *nvm_find_nvm_dev(const char *name)
127147
{
128148
struct nvm_dev *dev;
@@ -221,7 +241,6 @@ static void nvm_free(struct nvm_dev *dev)
221241

222242
static int nvm_init(struct nvm_dev *dev)
223243
{
224-
struct nvmm_type *mt;
225244
int ret = -EINVAL;
226245

227246
if (!dev->q || !dev->ops)
@@ -252,21 +271,13 @@ static int nvm_init(struct nvm_dev *dev)
252271
goto err;
253272
}
254273

255-
/* register with device with a supported manager */
256-
list_for_each_entry(mt, &nvm_mgrs, list) {
257-
ret = mt->register_mgr(dev);
258-
if (ret < 0)
259-
goto err; /* initialization failed */
260-
if (ret > 0) {
261-
dev->mt = mt;
262-
break; /* successfully initialized */
263-
}
264-
}
265-
266-
if (!ret) {
267-
pr_info("nvm: no compatible manager found.\n");
274+
down_write(&nvm_lock);
275+
ret = register_mgr(dev);
276+
up_write(&nvm_lock);
277+
if (ret < 0)
278+
goto err;
279+
if (!ret)
268280
return 0;
269-
}
270281

271282
pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n",
272283
dev->name, dev->sec_per_pg, dev->nr_planes,
@@ -337,15 +348,17 @@ EXPORT_SYMBOL(nvm_register);
337348

338349
void nvm_unregister(char *disk_name)
339350
{
340-
struct nvm_dev *dev = nvm_find_nvm_dev(disk_name);
351+
struct nvm_dev *dev;
341352

353+
down_write(&nvm_lock);
354+
dev = nvm_find_nvm_dev(disk_name);
342355
if (!dev) {
343356
pr_err("nvm: could not find device %s to unregister\n",
344357
disk_name);
358+
up_write(&nvm_lock);
345359
return;
346360
}
347361

348-
down_write(&nvm_lock);
349362
list_del(&dev->devices);
350363
up_write(&nvm_lock);
351364

@@ -363,38 +376,30 @@ static int nvm_create_target(struct nvm_dev *dev,
363376
{
364377
struct nvm_ioctl_create_simple *s = &create->conf.s;
365378
struct request_queue *tqueue;
366-
struct nvmm_type *mt;
367379
struct gendisk *tdisk;
368380
struct nvm_tgt_type *tt;
369381
struct nvm_target *t;
370382
void *targetdata;
371383
int ret = 0;
372384

385+
down_write(&nvm_lock);
373386
if (!dev->mt) {
374-
/* register with device with a supported NVM manager */
375-
list_for_each_entry(mt, &nvm_mgrs, list) {
376-
ret = mt->register_mgr(dev);
377-
if (ret < 0)
378-
return ret; /* initialization failed */
379-
if (ret > 0) {
380-
dev->mt = mt;
381-
break; /* successfully initialized */
382-
}
383-
}
384-
385-
if (!ret) {
386-
pr_info("nvm: no compatible nvm manager found.\n");
387-
return -ENODEV;
387+
ret = register_mgr(dev);
388+
if (!ret)
389+
ret = -ENODEV;
390+
if (ret < 0) {
391+
up_write(&nvm_lock);
392+
return ret;
388393
}
389394
}
390395

391396
tt = nvm_find_target_type(create->tgttype);
392397
if (!tt) {
393398
pr_err("nvm: target type %s not found\n", create->tgttype);
399+
up_write(&nvm_lock);
394400
return -EINVAL;
395401
}
396402

397-
down_write(&nvm_lock);
398403
list_for_each_entry(t, &dev->online_targets, list) {
399404
if (!strcmp(create->tgtname, t->disk->disk_name)) {
400405
pr_err("nvm: target name already exists.\n");
@@ -478,7 +483,9 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
478483
struct nvm_dev *dev;
479484
struct nvm_ioctl_create_simple *s;
480485

486+
down_write(&nvm_lock);
481487
dev = nvm_find_nvm_dev(create->dev);
488+
up_write(&nvm_lock);
482489
if (!dev) {
483490
pr_err("nvm: device not found\n");
484491
return -EINVAL;
@@ -537,7 +544,9 @@ static int nvm_configure_show(const char *val)
537544
return -EINVAL;
538545
}
539546

547+
down_write(&nvm_lock);
540548
dev = nvm_find_nvm_dev(devname);
549+
up_write(&nvm_lock);
541550
if (!dev) {
542551
pr_err("nvm: device not found\n");
543552
return -EINVAL;

0 commit comments

Comments
 (0)