@@ -52,14 +52,21 @@ static struct device_type disk_type;
52
52
*/
53
53
struct hd_struct * disk_get_part (struct gendisk * disk , int partno )
54
54
{
55
- struct hd_struct * part ;
55
+ struct hd_struct * part = NULL ;
56
+ struct disk_part_tbl * ptbl ;
56
57
57
- if (unlikely (partno < 0 || partno >= disk_max_parts ( disk ) ))
58
+ if (unlikely (partno < 0 ))
58
59
return NULL ;
60
+
59
61
rcu_read_lock ();
60
- part = rcu_dereference (disk -> __part [partno ]);
61
- if (part )
62
- get_device (part_to_dev (part ));
62
+
63
+ ptbl = rcu_dereference (disk -> part_tbl );
64
+ if (likely (partno < ptbl -> len )) {
65
+ part = rcu_dereference (ptbl -> part [partno ]);
66
+ if (part )
67
+ get_device (part_to_dev (part ));
68
+ }
69
+
63
70
rcu_read_unlock ();
64
71
65
72
return part ;
@@ -80,17 +87,24 @@ EXPORT_SYMBOL_GPL(disk_get_part);
80
87
void disk_part_iter_init (struct disk_part_iter * piter , struct gendisk * disk ,
81
88
unsigned int flags )
82
89
{
90
+ struct disk_part_tbl * ptbl ;
91
+
92
+ rcu_read_lock ();
93
+ ptbl = rcu_dereference (disk -> part_tbl );
94
+
83
95
piter -> disk = disk ;
84
96
piter -> part = NULL ;
85
97
86
98
if (flags & DISK_PITER_REVERSE )
87
- piter -> idx = disk_max_parts ( piter -> disk ) - 1 ;
99
+ piter -> idx = ptbl -> len - 1 ;
88
100
else if (flags & DISK_PITER_INCL_PART0 )
89
101
piter -> idx = 0 ;
90
102
else
91
103
piter -> idx = 1 ;
92
104
93
105
piter -> flags = flags ;
106
+
107
+ rcu_read_unlock ();
94
108
}
95
109
EXPORT_SYMBOL_GPL (disk_part_iter_init );
96
110
@@ -105,13 +119,16 @@ EXPORT_SYMBOL_GPL(disk_part_iter_init);
105
119
*/
106
120
struct hd_struct * disk_part_iter_next (struct disk_part_iter * piter )
107
121
{
122
+ struct disk_part_tbl * ptbl ;
108
123
int inc , end ;
109
124
110
125
/* put the last partition */
111
126
disk_put_part (piter -> part );
112
127
piter -> part = NULL ;
113
128
129
+ /* get part_tbl */
114
130
rcu_read_lock ();
131
+ ptbl = rcu_dereference (piter -> disk -> part_tbl );
115
132
116
133
/* determine iteration parameters */
117
134
if (piter -> flags & DISK_PITER_REVERSE ) {
@@ -122,14 +139,14 @@ struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter)
122
139
end = 0 ;
123
140
} else {
124
141
inc = 1 ;
125
- end = disk_max_parts ( piter -> disk ) ;
142
+ end = ptbl -> len ;
126
143
}
127
144
128
145
/* iterate to the next partition */
129
146
for (; piter -> idx != end ; piter -> idx += inc ) {
130
147
struct hd_struct * part ;
131
148
132
- part = rcu_dereference (piter -> disk -> __part [piter -> idx ]);
149
+ part = rcu_dereference (ptbl -> part [piter -> idx ]);
133
150
if (!part )
134
151
continue ;
135
152
if (!(piter -> flags & DISK_PITER_INCL_EMPTY ) && !part -> nr_sects )
@@ -180,10 +197,13 @@ EXPORT_SYMBOL_GPL(disk_part_iter_exit);
180
197
*/
181
198
struct hd_struct * disk_map_sector_rcu (struct gendisk * disk , sector_t sector )
182
199
{
200
+ struct disk_part_tbl * ptbl ;
183
201
int i ;
184
202
185
- for (i = 1 ; i < disk_max_parts (disk ); i ++ ) {
186
- struct hd_struct * part = rcu_dereference (disk -> __part [i ]);
203
+ ptbl = rcu_dereference (disk -> part_tbl );
204
+
205
+ for (i = 1 ; i < ptbl -> len ; i ++ ) {
206
+ struct hd_struct * part = rcu_dereference (ptbl -> part [i ]);
187
207
188
208
if (part && part -> start_sect <= sector &&
189
209
sector < part -> start_sect + part -> nr_sects )
@@ -798,12 +818,86 @@ static struct attribute_group *disk_attr_groups[] = {
798
818
NULL
799
819
};
800
820
821
+ static void disk_free_ptbl_rcu_cb (struct rcu_head * head )
822
+ {
823
+ struct disk_part_tbl * ptbl =
824
+ container_of (head , struct disk_part_tbl , rcu_head );
825
+
826
+ kfree (ptbl );
827
+ }
828
+
829
+ /**
830
+ * disk_replace_part_tbl - replace disk->part_tbl in RCU-safe way
831
+ * @disk: disk to replace part_tbl for
832
+ * @new_ptbl: new part_tbl to install
833
+ *
834
+ * Replace disk->part_tbl with @new_ptbl in RCU-safe way. The
835
+ * original ptbl is freed using RCU callback.
836
+ *
837
+ * LOCKING:
838
+ * Matching bd_mutx locked.
839
+ */
840
+ static void disk_replace_part_tbl (struct gendisk * disk ,
841
+ struct disk_part_tbl * new_ptbl )
842
+ {
843
+ struct disk_part_tbl * old_ptbl = disk -> part_tbl ;
844
+
845
+ rcu_assign_pointer (disk -> part_tbl , new_ptbl );
846
+ if (old_ptbl )
847
+ call_rcu (& old_ptbl -> rcu_head , disk_free_ptbl_rcu_cb );
848
+ }
849
+
850
+ /**
851
+ * disk_expand_part_tbl - expand disk->part_tbl
852
+ * @disk: disk to expand part_tbl for
853
+ * @partno: expand such that this partno can fit in
854
+ *
855
+ * Expand disk->part_tbl such that @partno can fit in. disk->part_tbl
856
+ * uses RCU to allow unlocked dereferencing for stats and other stuff.
857
+ *
858
+ * LOCKING:
859
+ * Matching bd_mutex locked, might sleep.
860
+ *
861
+ * RETURNS:
862
+ * 0 on success, -errno on failure.
863
+ */
864
+ int disk_expand_part_tbl (struct gendisk * disk , int partno )
865
+ {
866
+ struct disk_part_tbl * old_ptbl = disk -> part_tbl ;
867
+ struct disk_part_tbl * new_ptbl ;
868
+ int len = old_ptbl ? old_ptbl -> len : 0 ;
869
+ int target = partno + 1 ;
870
+ size_t size ;
871
+ int i ;
872
+
873
+ /* disk_max_parts() is zero during initialization, ignore if so */
874
+ if (disk_max_parts (disk ) && target > disk_max_parts (disk ))
875
+ return - EINVAL ;
876
+
877
+ if (target <= len )
878
+ return 0 ;
879
+
880
+ size = sizeof (* new_ptbl ) + target * sizeof (new_ptbl -> part [0 ]);
881
+ new_ptbl = kzalloc_node (size , GFP_KERNEL , disk -> node_id );
882
+ if (!new_ptbl )
883
+ return - ENOMEM ;
884
+
885
+ INIT_RCU_HEAD (& new_ptbl -> rcu_head );
886
+ new_ptbl -> len = target ;
887
+
888
+ for (i = 0 ; i < len ; i ++ )
889
+ rcu_assign_pointer (new_ptbl -> part [i ], old_ptbl -> part [i ]);
890
+
891
+ disk_replace_part_tbl (disk , new_ptbl );
892
+ return 0 ;
893
+ }
894
+
801
895
static void disk_release (struct device * dev )
802
896
{
803
897
struct gendisk * disk = dev_to_disk (dev );
804
898
805
899
kfree (disk -> random );
806
- kfree (disk -> __part );
900
+ disk_replace_part_tbl (disk , NULL );
807
901
free_part_stats (& disk -> part0 );
808
902
kfree (disk );
809
903
}
@@ -948,22 +1042,16 @@ struct gendisk *alloc_disk_ext_node(int minors, int ext_minors, int node_id)
948
1042
disk = kmalloc_node (sizeof (struct gendisk ),
949
1043
GFP_KERNEL | __GFP_ZERO , node_id );
950
1044
if (disk ) {
951
- int tot_minors = minors + ext_minors ;
952
- int size = tot_minors * sizeof (struct hd_struct * );
953
-
954
1045
if (!init_part_stats (& disk -> part0 )) {
955
1046
kfree (disk );
956
1047
return NULL ;
957
1048
}
958
-
959
- disk -> __part = kmalloc_node (size , GFP_KERNEL | __GFP_ZERO ,
960
- node_id );
961
- if (!disk -> __part ) {
962
- free_part_stats (& disk -> part0 );
1049
+ if (disk_expand_part_tbl (disk , 0 )) {
1050
+ free_part_stats (& disk -> part0 );
963
1051
kfree (disk );
964
1052
return NULL ;
965
1053
}
966
- disk -> __part [0 ] = & disk -> part0 ;
1054
+ disk -> part_tbl -> part [0 ] = & disk -> part0 ;
967
1055
968
1056
disk -> minors = minors ;
969
1057
disk -> ext_minors = ext_minors ;
@@ -973,6 +1061,7 @@ struct gendisk *alloc_disk_ext_node(int minors, int ext_minors, int node_id)
973
1061
device_initialize (disk_to_dev (disk ));
974
1062
INIT_WORK (& disk -> async_notify ,
975
1063
media_change_notify_thread );
1064
+ disk -> node_id = node_id ;
976
1065
}
977
1066
return disk ;
978
1067
}
0 commit comments