diff options
-rw-r--r-- | drivers/target/target_core_user.c | 46 |
1 files changed, 33 insertions, 13 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 9045837f748b..beb5f098f32d 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c | |||
@@ -97,7 +97,7 @@ struct tcmu_hba { | |||
97 | 97 | ||
98 | struct tcmu_dev { | 98 | struct tcmu_dev { |
99 | struct list_head node; | 99 | struct list_head node; |
100 | 100 | struct kref kref; | |
101 | struct se_device se_dev; | 101 | struct se_device se_dev; |
102 | 102 | ||
103 | char *name; | 103 | char *name; |
@@ -969,6 +969,7 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) | |||
969 | udev = kzalloc(sizeof(struct tcmu_dev), GFP_KERNEL); | 969 | udev = kzalloc(sizeof(struct tcmu_dev), GFP_KERNEL); |
970 | if (!udev) | 970 | if (!udev) |
971 | return NULL; | 971 | return NULL; |
972 | kref_init(&udev->kref); | ||
972 | 973 | ||
973 | udev->name = kstrdup(name, GFP_KERNEL); | 974 | udev->name = kstrdup(name, GFP_KERNEL); |
974 | if (!udev->name) { | 975 | if (!udev->name) { |
@@ -1145,6 +1146,24 @@ static int tcmu_open(struct uio_info *info, struct inode *inode) | |||
1145 | return 0; | 1146 | return 0; |
1146 | } | 1147 | } |
1147 | 1148 | ||
1149 | static void tcmu_dev_call_rcu(struct rcu_head *p) | ||
1150 | { | ||
1151 | struct se_device *dev = container_of(p, struct se_device, rcu_head); | ||
1152 | struct tcmu_dev *udev = TCMU_DEV(dev); | ||
1153 | |||
1154 | kfree(udev->uio_info.name); | ||
1155 | kfree(udev->name); | ||
1156 | kfree(udev); | ||
1157 | } | ||
1158 | |||
1159 | static void tcmu_dev_kref_release(struct kref *kref) | ||
1160 | { | ||
1161 | struct tcmu_dev *udev = container_of(kref, struct tcmu_dev, kref); | ||
1162 | struct se_device *dev = &udev->se_dev; | ||
1163 | |||
1164 | call_rcu(&dev->rcu_head, tcmu_dev_call_rcu); | ||
1165 | } | ||
1166 | |||
1148 | static int tcmu_release(struct uio_info *info, struct inode *inode) | 1167 | static int tcmu_release(struct uio_info *info, struct inode *inode) |
1149 | { | 1168 | { |
1150 | struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info); | 1169 | struct tcmu_dev *udev = container_of(info, struct tcmu_dev, uio_info); |
@@ -1152,7 +1171,8 @@ static int tcmu_release(struct uio_info *info, struct inode *inode) | |||
1152 | clear_bit(TCMU_DEV_BIT_OPEN, &udev->flags); | 1171 | clear_bit(TCMU_DEV_BIT_OPEN, &udev->flags); |
1153 | 1172 | ||
1154 | pr_debug("close\n"); | 1173 | pr_debug("close\n"); |
1155 | 1174 | /* release ref from configure */ | |
1175 | kref_put(&udev->kref, tcmu_dev_kref_release); | ||
1156 | return 0; | 1176 | return 0; |
1157 | } | 1177 | } |
1158 | 1178 | ||
@@ -1272,6 +1292,12 @@ static int tcmu_configure_device(struct se_device *dev) | |||
1272 | dev->dev_attrib.hw_max_sectors = 128; | 1292 | dev->dev_attrib.hw_max_sectors = 128; |
1273 | dev->dev_attrib.hw_queue_depth = 128; | 1293 | dev->dev_attrib.hw_queue_depth = 128; |
1274 | 1294 | ||
1295 | /* | ||
1296 | * Get a ref incase userspace does a close on the uio device before | ||
1297 | * LIO has initiated tcmu_free_device. | ||
1298 | */ | ||
1299 | kref_get(&udev->kref); | ||
1300 | |||
1275 | ret = tcmu_netlink_event(TCMU_CMD_ADDED_DEVICE, udev->uio_info.name, | 1301 | ret = tcmu_netlink_event(TCMU_CMD_ADDED_DEVICE, udev->uio_info.name, |
1276 | udev->uio_info.uio_dev->minor); | 1302 | udev->uio_info.uio_dev->minor); |
1277 | if (ret) | 1303 | if (ret) |
@@ -1284,11 +1310,13 @@ static int tcmu_configure_device(struct se_device *dev) | |||
1284 | return 0; | 1310 | return 0; |
1285 | 1311 | ||
1286 | err_netlink: | 1312 | err_netlink: |
1313 | kref_put(&udev->kref, tcmu_dev_kref_release); | ||
1287 | uio_unregister_device(&udev->uio_info); | 1314 | uio_unregister_device(&udev->uio_info); |
1288 | err_register: | 1315 | err_register: |
1289 | vfree(udev->mb_addr); | 1316 | vfree(udev->mb_addr); |
1290 | err_vzalloc: | 1317 | err_vzalloc: |
1291 | kfree(info->name); | 1318 | kfree(info->name); |
1319 | info->name = NULL; | ||
1292 | 1320 | ||
1293 | return ret; | 1321 | return ret; |
1294 | } | 1322 | } |
@@ -1302,14 +1330,6 @@ static int tcmu_check_and_free_pending_cmd(struct tcmu_cmd *cmd) | |||
1302 | return -EINVAL; | 1330 | return -EINVAL; |
1303 | } | 1331 | } |
1304 | 1332 | ||
1305 | static void tcmu_dev_call_rcu(struct rcu_head *p) | ||
1306 | { | ||
1307 | struct se_device *dev = container_of(p, struct se_device, rcu_head); | ||
1308 | struct tcmu_dev *udev = TCMU_DEV(dev); | ||
1309 | |||
1310 | kfree(udev); | ||
1311 | } | ||
1312 | |||
1313 | static bool tcmu_dev_configured(struct tcmu_dev *udev) | 1333 | static bool tcmu_dev_configured(struct tcmu_dev *udev) |
1314 | { | 1334 | { |
1315 | return udev->uio_info.uio_dev ? true : false; | 1335 | return udev->uio_info.uio_dev ? true : false; |
@@ -1364,10 +1384,10 @@ static void tcmu_free_device(struct se_device *dev) | |||
1364 | udev->uio_info.uio_dev->minor); | 1384 | udev->uio_info.uio_dev->minor); |
1365 | 1385 | ||
1366 | uio_unregister_device(&udev->uio_info); | 1386 | uio_unregister_device(&udev->uio_info); |
1367 | kfree(udev->uio_info.name); | ||
1368 | kfree(udev->name); | ||
1369 | } | 1387 | } |
1370 | call_rcu(&dev->rcu_head, tcmu_dev_call_rcu); | 1388 | |
1389 | /* release ref from init */ | ||
1390 | kref_put(&udev->kref, tcmu_dev_kref_release); | ||
1371 | } | 1391 | } |
1372 | 1392 | ||
1373 | enum { | 1393 | enum { |