diff options
Diffstat (limited to 'include/linux/genhd.h')
-rw-r--r-- | include/linux/genhd.h | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index ae0aaa9d42fa..4f440b3e89fe 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -97,7 +97,13 @@ struct partition_meta_info { | |||
97 | 97 | ||
98 | struct hd_struct { | 98 | struct hd_struct { |
99 | sector_t start_sect; | 99 | sector_t start_sect; |
100 | /* | ||
101 | * nr_sects is protected by sequence counter. One might extend a | ||
102 | * partition while IO is happening to it and update of nr_sects | ||
103 | * can be non-atomic on 32bit machines with 64bit sector_t. | ||
104 | */ | ||
100 | sector_t nr_sects; | 105 | sector_t nr_sects; |
106 | seqcount_t nr_sects_seq; | ||
101 | sector_t alignment_offset; | 107 | sector_t alignment_offset; |
102 | unsigned int discard_alignment; | 108 | unsigned int discard_alignment; |
103 | struct device __dev; | 109 | struct device __dev; |
@@ -647,6 +653,57 @@ static inline void hd_struct_put(struct hd_struct *part) | |||
647 | __delete_partition(part); | 653 | __delete_partition(part); |
648 | } | 654 | } |
649 | 655 | ||
656 | /* | ||
657 | * Any access of part->nr_sects which is not protected by partition | ||
658 | * bd_mutex or gendisk bdev bd_mutex, should be done using this | ||
659 | * accessor function. | ||
660 | * | ||
661 | * Code written along the lines of i_size_read() and i_size_write(). | ||
662 | * CONFIG_PREEMPT case optimizes the case of UP kernel with preemption | ||
663 | * on. | ||
664 | */ | ||
665 | static inline sector_t part_nr_sects_read(struct hd_struct *part) | ||
666 | { | ||
667 | #if BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_SMP) | ||
668 | sector_t nr_sects; | ||
669 | unsigned seq; | ||
670 | do { | ||
671 | seq = read_seqcount_begin(&part->nr_sects_seq); | ||
672 | nr_sects = part->nr_sects; | ||
673 | } while (read_seqcount_retry(&part->nr_sects_seq, seq)); | ||
674 | return nr_sects; | ||
675 | #elif BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_PREEMPT) | ||
676 | sector_t nr_sects; | ||
677 | |||
678 | preempt_disable(); | ||
679 | nr_sects = part->nr_sects; | ||
680 | preempt_enable(); | ||
681 | return nr_sects; | ||
682 | #else | ||
683 | return part->nr_sects; | ||
684 | #endif | ||
685 | } | ||
686 | |||
687 | /* | ||
688 | * Should be called with mutex lock held (typically bd_mutex) of partition | ||
689 | * to provide mutual exlusion among writers otherwise seqcount might be | ||
690 | * left in wrong state leaving the readers spinning infinitely. | ||
691 | */ | ||
692 | static inline void part_nr_sects_write(struct hd_struct *part, sector_t size) | ||
693 | { | ||
694 | #if BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_SMP) | ||
695 | write_seqcount_begin(&part->nr_sects_seq); | ||
696 | part->nr_sects = size; | ||
697 | write_seqcount_end(&part->nr_sects_seq); | ||
698 | #elif BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_PREEMPT) | ||
699 | preempt_disable(); | ||
700 | part->nr_sects = size; | ||
701 | preempt_enable(); | ||
702 | #else | ||
703 | part->nr_sects = size; | ||
704 | #endif | ||
705 | } | ||
706 | |||
650 | #else /* CONFIG_BLOCK */ | 707 | #else /* CONFIG_BLOCK */ |
651 | 708 | ||
652 | static inline void printk_all_partitions(void) { } | 709 | static inline void printk_all_partitions(void) { } |