diff --git a/drivers/block/blksnap/snapshot.c b/drivers/block/blksnap/snapshot.c index 1f28ff59d762..8063cc4b929e 100644 --- a/drivers/block/blksnap/snapshot.c +++ b/drivers/block/blksnap/snapshot.c @@ -28,7 +28,7 @@ static void snapshot_free(struct kref *kref) tracker = list_first_entry(&snapshot->trackers, struct tracker, link); - list_del(&tracker->link); + list_del_init(&tracker->link); tracker_release_snapshot(tracker); tracker_put(tracker); } @@ -160,14 +160,17 @@ int snapshot_add_device(const uuid_t *id, struct tracker *tracker) } } if (!ret) { - tracker_get(tracker); - list_add_tail(&tracker->link, &snapshot->trackers); + if (list_empty(&tracker->link)) { + tracker_get(tracker); + list_add_tail(&tracker->link, &snapshot->trackers); + } else + ret = -EBUSY; } up_write(&snapshot->rw_lock); snapshot_put(snapshot); - return 0; + return ret; } int snapshot_destroy(const uuid_t *id) diff --git a/drivers/block/blksnap/tracker.c b/drivers/block/blksnap/tracker.c index d98048dc5bed..008cc7f0f81e 100644 --- a/drivers/block/blksnap/tracker.c +++ b/drivers/block/blksnap/tracker.c @@ -79,6 +79,7 @@ static struct blkfilter *tracker_attach(struct block_device *bdev) return ERR_PTR(-ENOMEM); } + mutex_init(&tracker->ctl_lock); INIT_LIST_HEAD(&tracker->link); kref_init(&tracker->kref); tracker->dev_id = bdev->bd_dev; @@ -234,12 +235,17 @@ static int (*const ctl_table[])(struct tracker *tracker, static int tracker_ctl(struct blkfilter *flt, const unsigned int cmd, __u8 __user *buf, __u32 *plen) { + int ret = 0; struct tracker *tracker = container_of(flt, struct tracker, filter); if (cmd > ARRAY_SIZE(ctl_table)) return -ENOTTY; - return ctl_table[cmd](tracker, buf, plen); + mutex_lock(&tracker->ctl_lock); + ret = ctl_table[cmd](tracker, buf, plen); + mutex_unlock(&tracker->ctl_lock); + + return ret; } static struct blkfilter_operations tracker_ops = { diff --git a/drivers/block/blksnap/tracker.h b/drivers/block/blksnap/tracker.h index d0972994d528..dbf8295f9518 100644 --- a/drivers/block/blksnap/tracker.h +++ b/drivers/block/blksnap/tracker.h @@ -19,6 +19,9 @@ struct diff_area; * * @filter: * The block device filter structure. + * @ctl_lock: + * The mutex blocks simultaneous management of the tracker from different + * treads. * @link: * List header. Allows to combine trackers into a list in a snapshot. * @kref: @@ -41,6 +44,7 @@ struct diff_area; */ struct tracker { struct blkfilter filter; + struct mutex ctl_lock; struct list_head link; struct kref kref; dev_t dev_id;