aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2008-08-25 06:30:16 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:04 -0400
commit88e341261ca4d39eec21b212961c77eff51105f7 (patch)
treeb65315c446ce592e6a0dc521eab9acd92ae61c5e
parentec2cdedf798385a9397ac50dd0405dd658f8529c (diff)
block: update add_partition() error handling
d805dda4 tried to fix error case handling in add_partition() but had a few problems. * disk->part[] entry is set early and left dangling if operation fails. * Once device initialized, the last put_device() is responsible for freeing all the resources. The failure path freed part_stats and p regardless of put_device() causing double free. * holders subdir holds reference to the disk device, so failure path should remove it to release resources properly which was missing. This patch fixes the above problems and while at it move partition slot busy check into add_partition() for completeness and inlines holders subdirectory creation. Using separate function for it just obfuscates the code. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Abdel Benamrouche <draconux@gmail.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--block/ioctl.c7
-rw-r--r--fs/partitions/check.c40
2 files changed, 23 insertions, 24 deletions
diff --git a/block/ioctl.c b/block/ioctl.c
index c722de0ef2ee..eb046aeede8a 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -43,12 +43,9 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
43 || pstart < 0 || plength < 0) 43 || pstart < 0 || plength < 0)
44 return -EINVAL; 44 return -EINVAL;
45 } 45 }
46 /* partition number in use? */ 46
47 mutex_lock(&bdev->bd_mutex); 47 mutex_lock(&bdev->bd_mutex);
48 if (disk->part[part - 1]) { 48
49 mutex_unlock(&bdev->bd_mutex);
50 return -EBUSY;
51 }
52 /* overlap? */ 49 /* overlap? */
53 for (i = 0; i < disk->minors - 1; i++) { 50 for (i = 0; i < disk->minors - 1; i++) {
54 struct hd_struct *s = disk->part[i]; 51 struct hd_struct *s = disk->part[i];
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 68f3e41ae66f..16f98d824608 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -300,15 +300,6 @@ struct device_type part_type = {
300 .release = part_release, 300 .release = part_release,
301}; 301};
302 302
303static inline void partition_sysfs_add_subdir(struct hd_struct *p)
304{
305 struct kobject *k;
306
307 k = kobject_get(&p->dev.kobj);
308 p->holder_dir = kobject_create_and_add("holders", k);
309 kobject_put(k);
310}
311
312static inline void disk_sysfs_add_subdirs(struct gendisk *disk) 303static inline void disk_sysfs_add_subdirs(struct gendisk *disk)
313{ 304{
314 struct kobject *k; 305 struct kobject *k;
@@ -347,13 +338,16 @@ int add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
347 struct hd_struct *p; 338 struct hd_struct *p;
348 int err; 339 int err;
349 340
341 if (disk->part[part - 1])
342 return -EBUSY;
343
350 p = kzalloc(sizeof(*p), GFP_KERNEL); 344 p = kzalloc(sizeof(*p), GFP_KERNEL);
351 if (!p) 345 if (!p)
352 return -ENOMEM; 346 return -ENOMEM;
353 347
354 if (!init_part_stats(p)) { 348 if (!init_part_stats(p)) {
355 err = -ENOMEM; 349 err = -ENOMEM;
356 goto out0; 350 goto out_free;
357 } 351 }
358 p->start_sect = start; 352 p->start_sect = start;
359 p->nr_sects = len; 353 p->nr_sects = len;
@@ -372,34 +366,42 @@ int add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
372 p->dev.class = &block_class; 366 p->dev.class = &block_class;
373 p->dev.type = &part_type; 367 p->dev.type = &part_type;
374 p->dev.parent = &disk->dev; 368 p->dev.parent = &disk->dev;
375 disk->part[part-1] = p;
376 369
377 /* delay uevent until 'holders' subdir is created */ 370 /* delay uevent until 'holders' subdir is created */
378 p->dev.uevent_suppress = 1; 371 p->dev.uevent_suppress = 1;
379 err = device_add(&p->dev); 372 err = device_add(&p->dev);
380 if (err) 373 if (err)
381 goto out1; 374 goto out_put;
382 partition_sysfs_add_subdir(p); 375
376 err = -ENOMEM;
377 p->holder_dir = kobject_create_and_add("holders", &p->dev.kobj);
378 if (!p->holder_dir)
379 goto out_del;
380
383 p->dev.uevent_suppress = 0; 381 p->dev.uevent_suppress = 0;
384 if (flags & ADDPART_FLAG_WHOLEDISK) { 382 if (flags & ADDPART_FLAG_WHOLEDISK) {
385 err = device_create_file(&p->dev, &dev_attr_whole_disk); 383 err = device_create_file(&p->dev, &dev_attr_whole_disk);
386 if (err) 384 if (err)
387 goto out2; 385 goto out_del;
388 } 386 }
389 387
388 /* everything is up and running, commence */
389 disk->part[part - 1] = p;
390
390 /* suppress uevent if the disk supresses it */ 391 /* suppress uevent if the disk supresses it */
391 if (!disk->dev.uevent_suppress) 392 if (!disk->dev.uevent_suppress)
392 kobject_uevent(&p->dev.kobj, KOBJ_ADD); 393 kobject_uevent(&p->dev.kobj, KOBJ_ADD);
393 394
394 return 0; 395 return 0;
395 396
396out2: 397out_free:
398 kfree(p);
399 return err;
400out_del:
401 kobject_put(p->holder_dir);
397 device_del(&p->dev); 402 device_del(&p->dev);
398out1: 403out_put:
399 put_device(&p->dev); 404 put_device(&p->dev);
400 free_part_stats(p);
401out0:
402 kfree(p);
403 return err; 405 return err;
404} 406}
405 407