diff options
Diffstat (limited to 'fs/partitions/check.c')
-rw-r--r-- | fs/partitions/check.c | 315 |
1 files changed, 105 insertions, 210 deletions
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 9184215f3ef3..97f3f5f064ee 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -195,96 +195,45 @@ check_partition(struct gendisk *hd, struct block_device *bdev) | |||
195 | return ERR_PTR(res); | 195 | return ERR_PTR(res); |
196 | } | 196 | } |
197 | 197 | ||
198 | /* | 198 | static ssize_t part_start_show(struct device *dev, |
199 | * sysfs bindings for partitions | 199 | struct device_attribute *attr, char *buf) |
200 | */ | ||
201 | |||
202 | struct part_attribute { | ||
203 | struct attribute attr; | ||
204 | ssize_t (*show)(struct hd_struct *,char *); | ||
205 | ssize_t (*store)(struct hd_struct *,const char *, size_t); | ||
206 | }; | ||
207 | |||
208 | static ssize_t | ||
209 | part_attr_show(struct kobject * kobj, struct attribute * attr, char * page) | ||
210 | { | 200 | { |
211 | struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); | 201 | struct hd_struct *p = dev_to_part(dev); |
212 | struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); | ||
213 | ssize_t ret = 0; | ||
214 | if (part_attr->show) | ||
215 | ret = part_attr->show(p, page); | ||
216 | return ret; | ||
217 | } | ||
218 | static ssize_t | ||
219 | part_attr_store(struct kobject * kobj, struct attribute * attr, | ||
220 | const char *page, size_t count) | ||
221 | { | ||
222 | struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); | ||
223 | struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); | ||
224 | ssize_t ret = 0; | ||
225 | 202 | ||
226 | if (part_attr->store) | 203 | return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect); |
227 | ret = part_attr->store(p, page, count); | ||
228 | return ret; | ||
229 | } | 204 | } |
230 | 205 | ||
231 | static struct sysfs_ops part_sysfs_ops = { | 206 | static ssize_t part_size_show(struct device *dev, |
232 | .show = part_attr_show, | 207 | struct device_attribute *attr, char *buf) |
233 | .store = part_attr_store, | ||
234 | }; | ||
235 | |||
236 | static ssize_t part_uevent_store(struct hd_struct * p, | ||
237 | const char *page, size_t count) | ||
238 | { | 208 | { |
239 | kobject_uevent(&p->kobj, KOBJ_ADD); | 209 | struct hd_struct *p = dev_to_part(dev); |
240 | return count; | 210 | return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects); |
241 | } | 211 | } |
242 | static ssize_t part_dev_read(struct hd_struct * p, char *page) | 212 | |
243 | { | 213 | static ssize_t part_stat_show(struct device *dev, |
244 | struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj); | 214 | struct device_attribute *attr, char *buf) |
245 | dev_t dev = MKDEV(disk->major, disk->first_minor + p->partno); | ||
246 | return print_dev_t(page, dev); | ||
247 | } | ||
248 | static ssize_t part_start_read(struct hd_struct * p, char *page) | ||
249 | { | ||
250 | return sprintf(page, "%llu\n",(unsigned long long)p->start_sect); | ||
251 | } | ||
252 | static ssize_t part_size_read(struct hd_struct * p, char *page) | ||
253 | { | ||
254 | return sprintf(page, "%llu\n",(unsigned long long)p->nr_sects); | ||
255 | } | ||
256 | static ssize_t part_stat_read(struct hd_struct * p, char *page) | ||
257 | { | 215 | { |
258 | return sprintf(page, "%8u %8llu %8u %8llu\n", | 216 | struct hd_struct *p = dev_to_part(dev); |
217 | |||
218 | return sprintf(buf, "%8u %8llu %8u %8llu\n", | ||
259 | p->ios[0], (unsigned long long)p->sectors[0], | 219 | p->ios[0], (unsigned long long)p->sectors[0], |
260 | p->ios[1], (unsigned long long)p->sectors[1]); | 220 | p->ios[1], (unsigned long long)p->sectors[1]); |
261 | } | 221 | } |
262 | static struct part_attribute part_attr_uevent = { | ||
263 | .attr = {.name = "uevent", .mode = S_IWUSR }, | ||
264 | .store = part_uevent_store | ||
265 | }; | ||
266 | static struct part_attribute part_attr_dev = { | ||
267 | .attr = {.name = "dev", .mode = S_IRUGO }, | ||
268 | .show = part_dev_read | ||
269 | }; | ||
270 | static struct part_attribute part_attr_start = { | ||
271 | .attr = {.name = "start", .mode = S_IRUGO }, | ||
272 | .show = part_start_read | ||
273 | }; | ||
274 | static struct part_attribute part_attr_size = { | ||
275 | .attr = {.name = "size", .mode = S_IRUGO }, | ||
276 | .show = part_size_read | ||
277 | }; | ||
278 | static struct part_attribute part_attr_stat = { | ||
279 | .attr = {.name = "stat", .mode = S_IRUGO }, | ||
280 | .show = part_stat_read | ||
281 | }; | ||
282 | 222 | ||
283 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 223 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
224 | static ssize_t part_fail_show(struct device *dev, | ||
225 | struct device_attribute *attr, char *buf) | ||
226 | { | ||
227 | struct hd_struct *p = dev_to_part(dev); | ||
284 | 228 | ||
285 | static ssize_t part_fail_store(struct hd_struct * p, | 229 | return sprintf(buf, "%d\n", p->make_it_fail); |
230 | } | ||
231 | |||
232 | static ssize_t part_fail_store(struct device *dev, | ||
233 | struct device_attribute *attr, | ||
286 | const char *buf, size_t count) | 234 | const char *buf, size_t count) |
287 | { | 235 | { |
236 | struct hd_struct *p = dev_to_part(dev); | ||
288 | int i; | 237 | int i; |
289 | 238 | ||
290 | if (count > 0 && sscanf(buf, "%d", &i) > 0) | 239 | if (count > 0 && sscanf(buf, "%d", &i) > 0) |
@@ -292,49 +241,52 @@ static ssize_t part_fail_store(struct hd_struct * p, | |||
292 | 241 | ||
293 | return count; | 242 | return count; |
294 | } | 243 | } |
295 | static ssize_t part_fail_read(struct hd_struct * p, char *page) | 244 | #endif |
296 | { | ||
297 | return sprintf(page, "%d\n", p->make_it_fail); | ||
298 | } | ||
299 | static struct part_attribute part_attr_fail = { | ||
300 | .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, | ||
301 | .store = part_fail_store, | ||
302 | .show = part_fail_read | ||
303 | }; | ||
304 | 245 | ||
246 | static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); | ||
247 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); | ||
248 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); | ||
249 | #ifdef CONFIG_FAIL_MAKE_REQUEST | ||
250 | static struct device_attribute dev_attr_fail = | ||
251 | __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); | ||
305 | #endif | 252 | #endif |
306 | 253 | ||
307 | static struct attribute * default_attrs[] = { | 254 | static struct attribute *part_attrs[] = { |
308 | &part_attr_uevent.attr, | 255 | &dev_attr_start.attr, |
309 | &part_attr_dev.attr, | 256 | &dev_attr_size.attr, |
310 | &part_attr_start.attr, | 257 | &dev_attr_stat.attr, |
311 | &part_attr_size.attr, | ||
312 | &part_attr_stat.attr, | ||
313 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 258 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
314 | &part_attr_fail.attr, | 259 | &dev_attr_fail.attr, |
315 | #endif | 260 | #endif |
316 | NULL, | 261 | NULL |
317 | }; | 262 | }; |
318 | 263 | ||
319 | extern struct kset *block_kset; | 264 | static struct attribute_group part_attr_group = { |
265 | .attrs = part_attrs, | ||
266 | }; | ||
320 | 267 | ||
321 | static void part_release(struct kobject *kobj) | 268 | static struct attribute_group *part_attr_groups[] = { |
269 | &part_attr_group, | ||
270 | NULL | ||
271 | }; | ||
272 | |||
273 | static void part_release(struct device *dev) | ||
322 | { | 274 | { |
323 | struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); | 275 | struct hd_struct *p = dev_to_part(dev); |
324 | kfree(p); | 276 | kfree(p); |
325 | } | 277 | } |
326 | 278 | ||
327 | struct kobj_type ktype_part = { | 279 | struct device_type part_type = { |
280 | .name = "partition", | ||
281 | .groups = part_attr_groups, | ||
328 | .release = part_release, | 282 | .release = part_release, |
329 | .default_attrs = default_attrs, | ||
330 | .sysfs_ops = &part_sysfs_ops, | ||
331 | }; | 283 | }; |
332 | 284 | ||
333 | static inline void partition_sysfs_add_subdir(struct hd_struct *p) | 285 | static inline void partition_sysfs_add_subdir(struct hd_struct *p) |
334 | { | 286 | { |
335 | struct kobject *k; | 287 | struct kobject *k; |
336 | 288 | ||
337 | k = kobject_get(&p->kobj); | 289 | k = kobject_get(&p->dev.kobj); |
338 | p->holder_dir = kobject_create_and_add("holders", k); | 290 | p->holder_dir = kobject_create_and_add("holders", k); |
339 | kobject_put(k); | 291 | kobject_put(k); |
340 | } | 292 | } |
@@ -343,7 +295,7 @@ static inline void disk_sysfs_add_subdirs(struct gendisk *disk) | |||
343 | { | 295 | { |
344 | struct kobject *k; | 296 | struct kobject *k; |
345 | 297 | ||
346 | k = kobject_get(&disk->kobj); | 298 | k = kobject_get(&disk->dev.kobj); |
347 | disk->holder_dir = kobject_create_and_add("holders", k); | 299 | disk->holder_dir = kobject_create_and_add("holders", k); |
348 | disk->slave_dir = kobject_create_and_add("slaves", k); | 300 | disk->slave_dir = kobject_create_and_add("slaves", k); |
349 | kobject_put(k); | 301 | kobject_put(k); |
@@ -352,6 +304,7 @@ static inline void disk_sysfs_add_subdirs(struct gendisk *disk) | |||
352 | void delete_partition(struct gendisk *disk, int part) | 304 | void delete_partition(struct gendisk *disk, int part) |
353 | { | 305 | { |
354 | struct hd_struct *p = disk->part[part-1]; | 306 | struct hd_struct *p = disk->part[part-1]; |
307 | |||
355 | if (!p) | 308 | if (!p) |
356 | return; | 309 | return; |
357 | if (!p->nr_sects) | 310 | if (!p->nr_sects) |
@@ -361,113 +314,55 @@ void delete_partition(struct gendisk *disk, int part) | |||
361 | p->nr_sects = 0; | 314 | p->nr_sects = 0; |
362 | p->ios[0] = p->ios[1] = 0; | 315 | p->ios[0] = p->ios[1] = 0; |
363 | p->sectors[0] = p->sectors[1] = 0; | 316 | p->sectors[0] = p->sectors[1] = 0; |
364 | sysfs_remove_link(&p->kobj, "subsystem"); | ||
365 | kobject_unregister(p->holder_dir); | 317 | kobject_unregister(p->holder_dir); |
366 | kobject_uevent(&p->kobj, KOBJ_REMOVE); | 318 | device_del(&p->dev); |
367 | kobject_del(&p->kobj); | 319 | put_device(&p->dev); |
368 | kobject_put(&p->kobj); | ||
369 | } | 320 | } |
370 | 321 | ||
371 | void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) | 322 | void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) |
372 | { | 323 | { |
373 | struct hd_struct *p; | 324 | struct hd_struct *p; |
325 | int err; | ||
374 | 326 | ||
375 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 327 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
376 | if (!p) | 328 | if (!p) |
377 | return; | 329 | return; |
378 | 330 | ||
379 | p->start_sect = start; | 331 | p->start_sect = start; |
380 | p->nr_sects = len; | 332 | p->nr_sects = len; |
381 | p->partno = part; | 333 | p->partno = part; |
382 | p->policy = disk->policy; | 334 | p->policy = disk->policy; |
383 | 335 | ||
384 | if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1])) | 336 | if (isdigit(disk->dev.bus_id[strlen(disk->dev.bus_id)-1])) |
385 | kobject_set_name(&p->kobj, "%sp%d", | 337 | snprintf(p->dev.bus_id, BUS_ID_SIZE, |
386 | kobject_name(&disk->kobj), part); | 338 | "%sp%d", disk->dev.bus_id, part); |
387 | else | 339 | else |
388 | kobject_set_name(&p->kobj, "%s%d", | 340 | snprintf(p->dev.bus_id, BUS_ID_SIZE, |
389 | kobject_name(&disk->kobj),part); | 341 | "%s%d", disk->dev.bus_id, part); |
390 | p->kobj.parent = &disk->kobj; | 342 | |
391 | p->kobj.ktype = &ktype_part; | 343 | device_initialize(&p->dev); |
392 | kobject_init(&p->kobj); | 344 | p->dev.devt = MKDEV(disk->major, disk->first_minor + part); |
393 | kobject_add(&p->kobj); | 345 | p->dev.class = &block_class; |
394 | if (!disk->part_uevent_suppress) | 346 | p->dev.type = &part_type; |
395 | kobject_uevent(&p->kobj, KOBJ_ADD); | 347 | p->dev.parent = &disk->dev; |
396 | sysfs_create_link(&p->kobj, &block_kset->kobj, "subsystem"); | 348 | disk->part[part-1] = p; |
349 | |||
350 | /* delay uevent until 'holders' subdir is created */ | ||
351 | p->dev.uevent_suppress = 1; | ||
352 | device_add(&p->dev); | ||
353 | partition_sysfs_add_subdir(p); | ||
354 | p->dev.uevent_suppress = 0; | ||
397 | if (flags & ADDPART_FLAG_WHOLEDISK) { | 355 | if (flags & ADDPART_FLAG_WHOLEDISK) { |
398 | static struct attribute addpartattr = { | 356 | static struct attribute addpartattr = { |
399 | .name = "whole_disk", | 357 | .name = "whole_disk", |
400 | .mode = S_IRUSR | S_IRGRP | S_IROTH, | 358 | .mode = S_IRUSR | S_IRGRP | S_IROTH, |
401 | }; | 359 | }; |
402 | 360 | err = sysfs_create_file(&p->dev.kobj, &addpartattr); | |
403 | sysfs_create_file(&p->kobj, &addpartattr); | ||
404 | } | 361 | } |
405 | partition_sysfs_add_subdir(p); | ||
406 | disk->part[part-1] = p; | ||
407 | } | ||
408 | 362 | ||
409 | static char *make_block_name(struct gendisk *disk) | 363 | /* suppress uevent if the disk supresses it */ |
410 | { | 364 | if (!disk->dev.uevent_suppress) |
411 | char *name; | 365 | kobject_uevent(&p->dev.kobj, KOBJ_ADD); |
412 | static char *block_str = "block:"; | ||
413 | int size; | ||
414 | char *s; | ||
415 | |||
416 | size = strlen(block_str) + strlen(disk->disk_name) + 1; | ||
417 | name = kmalloc(size, GFP_KERNEL); | ||
418 | if (!name) | ||
419 | return NULL; | ||
420 | strcpy(name, block_str); | ||
421 | strcat(name, disk->disk_name); | ||
422 | /* ewww... some of these buggers have / in name... */ | ||
423 | s = strchr(name, '/'); | ||
424 | if (s) | ||
425 | *s = '!'; | ||
426 | return name; | ||
427 | } | ||
428 | |||
429 | static int disk_sysfs_symlinks(struct gendisk *disk) | ||
430 | { | ||
431 | struct device *target = get_device(disk->driverfs_dev); | ||
432 | int err; | ||
433 | char *disk_name = NULL; | ||
434 | |||
435 | if (target) { | ||
436 | disk_name = make_block_name(disk); | ||
437 | if (!disk_name) { | ||
438 | err = -ENOMEM; | ||
439 | goto err_out; | ||
440 | } | ||
441 | |||
442 | err = sysfs_create_link(&disk->kobj, &target->kobj, "device"); | ||
443 | if (err) | ||
444 | goto err_out_disk_name; | ||
445 | |||
446 | err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name); | ||
447 | if (err) | ||
448 | goto err_out_dev_link; | ||
449 | } | ||
450 | |||
451 | err = sysfs_create_link(&disk->kobj, &block_kset->kobj, | ||
452 | "subsystem"); | ||
453 | if (err) | ||
454 | goto err_out_disk_name_lnk; | ||
455 | |||
456 | kfree(disk_name); | ||
457 | |||
458 | return 0; | ||
459 | |||
460 | err_out_disk_name_lnk: | ||
461 | if (target) { | ||
462 | sysfs_remove_link(&target->kobj, disk_name); | ||
463 | err_out_dev_link: | ||
464 | sysfs_remove_link(&disk->kobj, "device"); | ||
465 | err_out_disk_name: | ||
466 | kfree(disk_name); | ||
467 | err_out: | ||
468 | put_device(target); | ||
469 | } | ||
470 | return err; | ||
471 | } | 366 | } |
472 | 367 | ||
473 | /* Not exported, helper to add_disk(). */ | 368 | /* Not exported, helper to add_disk(). */ |
@@ -479,19 +374,29 @@ void register_disk(struct gendisk *disk) | |||
479 | struct hd_struct *p; | 374 | struct hd_struct *p; |
480 | int err; | 375 | int err; |
481 | 376 | ||
482 | kobject_set_name(&disk->kobj, "%s", disk->disk_name); | 377 | disk->dev.parent = disk->driverfs_dev; |
483 | /* ewww... some of these buggers have / in name... */ | 378 | disk->dev.devt = MKDEV(disk->major, disk->first_minor); |
484 | s = strchr(disk->kobj.k_name, '/'); | 379 | |
380 | strlcpy(disk->dev.bus_id, disk->disk_name, KOBJ_NAME_LEN); | ||
381 | /* ewww... some of these buggers have / in the name... */ | ||
382 | s = strchr(disk->dev.bus_id, '/'); | ||
485 | if (s) | 383 | if (s) |
486 | *s = '!'; | 384 | *s = '!'; |
487 | if ((err = kobject_add(&disk->kobj))) | 385 | |
386 | /* delay uevents, until we scanned partition table */ | ||
387 | disk->dev.uevent_suppress = 1; | ||
388 | |||
389 | if (device_add(&disk->dev)) | ||
488 | return; | 390 | return; |
489 | err = disk_sysfs_symlinks(disk); | 391 | #ifndef CONFIG_SYSFS_DEPRECATED |
392 | err = sysfs_create_link(block_depr, &disk->dev.kobj, | ||
393 | kobject_name(&disk->dev.kobj)); | ||
490 | if (err) { | 394 | if (err) { |
491 | kobject_del(&disk->kobj); | 395 | device_del(&disk->dev); |
492 | return; | 396 | return; |
493 | } | 397 | } |
494 | disk_sysfs_add_subdirs(disk); | 398 | #endif |
399 | disk_sysfs_add_subdirs(disk); | ||
495 | 400 | ||
496 | /* No minors to use for partitions */ | 401 | /* No minors to use for partitions */ |
497 | if (disk->minors == 1) | 402 | if (disk->minors == 1) |
@@ -505,25 +410,23 @@ void register_disk(struct gendisk *disk) | |||
505 | if (!bdev) | 410 | if (!bdev) |
506 | goto exit; | 411 | goto exit; |
507 | 412 | ||
508 | /* scan partition table, but suppress uevents */ | ||
509 | bdev->bd_invalidated = 1; | 413 | bdev->bd_invalidated = 1; |
510 | disk->part_uevent_suppress = 1; | ||
511 | err = blkdev_get(bdev, FMODE_READ, 0); | 414 | err = blkdev_get(bdev, FMODE_READ, 0); |
512 | disk->part_uevent_suppress = 0; | ||
513 | if (err < 0) | 415 | if (err < 0) |
514 | goto exit; | 416 | goto exit; |
515 | blkdev_put(bdev); | 417 | blkdev_put(bdev); |
516 | 418 | ||
517 | exit: | 419 | exit: |
518 | /* announce disk after possible partitions are already created */ | 420 | /* announce disk after possible partitions are created */ |
519 | kobject_uevent(&disk->kobj, KOBJ_ADD); | 421 | disk->dev.uevent_suppress = 0; |
422 | kobject_uevent(&disk->dev.kobj, KOBJ_ADD); | ||
520 | 423 | ||
521 | /* announce possible partitions */ | 424 | /* announce possible partitions */ |
522 | for (i = 1; i < disk->minors; i++) { | 425 | for (i = 1; i < disk->minors; i++) { |
523 | p = disk->part[i-1]; | 426 | p = disk->part[i-1]; |
524 | if (!p || !p->nr_sects) | 427 | if (!p || !p->nr_sects) |
525 | continue; | 428 | continue; |
526 | kobject_uevent(&p->kobj, KOBJ_ADD); | 429 | kobject_uevent(&p->dev.kobj, KOBJ_ADD); |
527 | } | 430 | } |
528 | } | 431 | } |
529 | 432 | ||
@@ -602,19 +505,11 @@ void del_gendisk(struct gendisk *disk) | |||
602 | disk_stat_set_all(disk, 0); | 505 | disk_stat_set_all(disk, 0); |
603 | disk->stamp = 0; | 506 | disk->stamp = 0; |
604 | 507 | ||
605 | kobject_uevent(&disk->kobj, KOBJ_REMOVE); | ||
606 | kobject_unregister(disk->holder_dir); | 508 | kobject_unregister(disk->holder_dir); |
607 | kobject_unregister(disk->slave_dir); | 509 | kobject_unregister(disk->slave_dir); |
608 | if (disk->driverfs_dev) { | 510 | disk->driverfs_dev = NULL; |
609 | char *disk_name = make_block_name(disk); | 511 | #ifndef CONFIG_SYSFS_DEPRECATED |
610 | sysfs_remove_link(&disk->kobj, "device"); | 512 | sysfs_remove_link(block_depr, disk->dev.bus_id); |
611 | if (disk_name) { | 513 | #endif |
612 | sysfs_remove_link(&disk->driverfs_dev->kobj, disk_name); | 514 | device_del(&disk->dev); |
613 | kfree(disk_name); | ||
614 | } | ||
615 | put_device(disk->driverfs_dev); | ||
616 | disk->driverfs_dev = NULL; | ||
617 | } | ||
618 | sysfs_remove_link(&disk->kobj, "subsystem"); | ||
619 | kobject_del(&disk->kobj); | ||
620 | } | 515 | } |