Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * Block device concurrent positioning ranges.
4 : *
5 : * Copyright (C) 2021 Western Digital Corporation or its Affiliates.
6 : */
7 : #include <linux/kernel.h>
8 : #include <linux/blkdev.h>
9 : #include <linux/slab.h>
10 : #include <linux/init.h>
11 :
12 : #include "blk.h"
13 :
14 : static ssize_t
15 0 : blk_ia_range_sector_show(struct blk_independent_access_range *iar,
16 : char *buf)
17 : {
18 0 : return sprintf(buf, "%llu\n", iar->sector);
19 : }
20 :
21 : static ssize_t
22 0 : blk_ia_range_nr_sectors_show(struct blk_independent_access_range *iar,
23 : char *buf)
24 : {
25 0 : return sprintf(buf, "%llu\n", iar->nr_sectors);
26 : }
27 :
28 : struct blk_ia_range_sysfs_entry {
29 : struct attribute attr;
30 : ssize_t (*show)(struct blk_independent_access_range *iar, char *buf);
31 : };
32 :
33 : static struct blk_ia_range_sysfs_entry blk_ia_range_sector_entry = {
34 : .attr = { .name = "sector", .mode = 0444 },
35 : .show = blk_ia_range_sector_show,
36 : };
37 :
38 : static struct blk_ia_range_sysfs_entry blk_ia_range_nr_sectors_entry = {
39 : .attr = { .name = "nr_sectors", .mode = 0444 },
40 : .show = blk_ia_range_nr_sectors_show,
41 : };
42 :
43 : static struct attribute *blk_ia_range_attrs[] = {
44 : &blk_ia_range_sector_entry.attr,
45 : &blk_ia_range_nr_sectors_entry.attr,
46 : NULL,
47 : };
48 : ATTRIBUTE_GROUPS(blk_ia_range);
49 :
50 0 : static ssize_t blk_ia_range_sysfs_show(struct kobject *kobj,
51 : struct attribute *attr, char *buf)
52 : {
53 0 : struct blk_ia_range_sysfs_entry *entry =
54 0 : container_of(attr, struct blk_ia_range_sysfs_entry, attr);
55 0 : struct blk_independent_access_range *iar =
56 0 : container_of(kobj, struct blk_independent_access_range, kobj);
57 : ssize_t ret;
58 :
59 0 : mutex_lock(&iar->queue->sysfs_lock);
60 0 : ret = entry->show(iar, buf);
61 0 : mutex_unlock(&iar->queue->sysfs_lock);
62 :
63 0 : return ret;
64 : }
65 :
66 : static const struct sysfs_ops blk_ia_range_sysfs_ops = {
67 : .show = blk_ia_range_sysfs_show,
68 : };
69 :
70 : /*
71 : * Independent access range entries are not freed individually, but alltogether
72 : * with struct blk_independent_access_ranges and its array of ranges. Since
73 : * kobject_add() takes a reference on the parent kobject contained in
74 : * struct blk_independent_access_ranges, the array of independent access range
75 : * entries cannot be freed until kobject_del() is called for all entries.
76 : * So we do not need to do anything here, but still need this no-op release
77 : * operation to avoid complaints from the kobject code.
78 : */
79 0 : static void blk_ia_range_sysfs_nop_release(struct kobject *kobj)
80 : {
81 0 : }
82 :
83 : static struct kobj_type blk_ia_range_ktype = {
84 : .sysfs_ops = &blk_ia_range_sysfs_ops,
85 : .default_groups = blk_ia_range_groups,
86 : .release = blk_ia_range_sysfs_nop_release,
87 : };
88 :
89 : /*
90 : * This will be executed only after all independent access range entries are
91 : * removed with kobject_del(), at which point, it is safe to free everything,
92 : * including the array of ranges.
93 : */
94 0 : static void blk_ia_ranges_sysfs_release(struct kobject *kobj)
95 : {
96 0 : struct blk_independent_access_ranges *iars =
97 0 : container_of(kobj, struct blk_independent_access_ranges, kobj);
98 :
99 0 : kfree(iars);
100 0 : }
101 :
102 : static struct kobj_type blk_ia_ranges_ktype = {
103 : .release = blk_ia_ranges_sysfs_release,
104 : };
105 :
106 : /**
107 : * disk_register_independent_access_ranges - register with sysfs a set of
108 : * independent access ranges
109 : * @disk: Target disk
110 : * @new_iars: New set of independent access ranges
111 : *
112 : * Register with sysfs a set of independent access ranges for @disk.
113 : * If @new_iars is not NULL, this set of ranges is registered and the old set
114 : * specified by q->ia_ranges is unregistered. Otherwise, q->ia_ranges is
115 : * registered if it is not already.
116 : */
117 0 : int disk_register_independent_access_ranges(struct gendisk *disk,
118 : struct blk_independent_access_ranges *new_iars)
119 : {
120 0 : struct request_queue *q = disk->queue;
121 : struct blk_independent_access_ranges *iars;
122 : int i, ret;
123 :
124 : lockdep_assert_held(&q->sysfs_dir_lock);
125 : lockdep_assert_held(&q->sysfs_lock);
126 :
127 : /* If a new range set is specified, unregister the old one */
128 0 : if (new_iars) {
129 0 : if (q->ia_ranges)
130 0 : disk_unregister_independent_access_ranges(disk);
131 0 : q->ia_ranges = new_iars;
132 : }
133 :
134 0 : iars = q->ia_ranges;
135 0 : if (!iars)
136 : return 0;
137 :
138 : /*
139 : * At this point, iars is the new set of sector access ranges that needs
140 : * to be registered with sysfs.
141 : */
142 0 : WARN_ON(iars->sysfs_registered);
143 0 : ret = kobject_init_and_add(&iars->kobj, &blk_ia_ranges_ktype,
144 : &q->kobj, "%s", "independent_access_ranges");
145 0 : if (ret) {
146 0 : q->ia_ranges = NULL;
147 0 : kobject_put(&iars->kobj);
148 0 : return ret;
149 : }
150 :
151 0 : for (i = 0; i < iars->nr_ia_ranges; i++) {
152 0 : iars->ia_range[i].queue = q;
153 0 : ret = kobject_init_and_add(&iars->ia_range[i].kobj,
154 : &blk_ia_range_ktype, &iars->kobj,
155 : "%d", i);
156 0 : if (ret) {
157 0 : while (--i >= 0)
158 0 : kobject_del(&iars->ia_range[i].kobj);
159 0 : kobject_del(&iars->kobj);
160 0 : kobject_put(&iars->kobj);
161 0 : return ret;
162 : }
163 : }
164 :
165 0 : iars->sysfs_registered = true;
166 :
167 0 : return 0;
168 : }
169 :
170 0 : void disk_unregister_independent_access_ranges(struct gendisk *disk)
171 : {
172 0 : struct request_queue *q = disk->queue;
173 0 : struct blk_independent_access_ranges *iars = q->ia_ranges;
174 : int i;
175 :
176 : lockdep_assert_held(&q->sysfs_dir_lock);
177 : lockdep_assert_held(&q->sysfs_lock);
178 :
179 0 : if (!iars)
180 : return;
181 :
182 0 : if (iars->sysfs_registered) {
183 0 : for (i = 0; i < iars->nr_ia_ranges; i++)
184 0 : kobject_del(&iars->ia_range[i].kobj);
185 0 : kobject_del(&iars->kobj);
186 0 : kobject_put(&iars->kobj);
187 : } else {
188 0 : kfree(iars);
189 : }
190 :
191 0 : q->ia_ranges = NULL;
192 : }
193 :
194 : static struct blk_independent_access_range *
195 : disk_find_ia_range(struct blk_independent_access_ranges *iars,
196 : sector_t sector)
197 : {
198 : struct blk_independent_access_range *iar;
199 : int i;
200 :
201 0 : for (i = 0; i < iars->nr_ia_ranges; i++) {
202 0 : iar = &iars->ia_range[i];
203 0 : if (sector >= iar->sector &&
204 0 : sector < iar->sector + iar->nr_sectors)
205 : return iar;
206 : }
207 :
208 : return NULL;
209 : }
210 :
211 0 : static bool disk_check_ia_ranges(struct gendisk *disk,
212 : struct blk_independent_access_ranges *iars)
213 : {
214 : struct blk_independent_access_range *iar, *tmp;
215 0 : sector_t capacity = get_capacity(disk);
216 0 : sector_t sector = 0;
217 : int i;
218 :
219 : /*
220 : * While sorting the ranges in increasing LBA order, check that the
221 : * ranges do not overlap, that there are no sector holes and that all
222 : * sectors belong to one range.
223 : */
224 0 : for (i = 0; i < iars->nr_ia_ranges; i++) {
225 0 : tmp = disk_find_ia_range(iars, sector);
226 0 : if (!tmp || tmp->sector != sector) {
227 0 : pr_warn("Invalid non-contiguous independent access ranges\n");
228 0 : return false;
229 : }
230 :
231 0 : iar = &iars->ia_range[i];
232 0 : if (tmp != iar) {
233 0 : swap(iar->sector, tmp->sector);
234 0 : swap(iar->nr_sectors, tmp->nr_sectors);
235 : }
236 :
237 0 : sector += iar->nr_sectors;
238 : }
239 :
240 0 : if (sector != capacity) {
241 0 : pr_warn("Independent access ranges do not match disk capacity\n");
242 0 : return false;
243 : }
244 :
245 : return true;
246 : }
247 :
248 : static bool disk_ia_ranges_changed(struct gendisk *disk,
249 : struct blk_independent_access_ranges *new)
250 : {
251 0 : struct blk_independent_access_ranges *old = disk->queue->ia_ranges;
252 : int i;
253 :
254 0 : if (!old)
255 : return true;
256 :
257 0 : if (old->nr_ia_ranges != new->nr_ia_ranges)
258 : return true;
259 :
260 0 : for (i = 0; i < old->nr_ia_ranges; i++) {
261 0 : if (new->ia_range[i].sector != old->ia_range[i].sector ||
262 0 : new->ia_range[i].nr_sectors != old->ia_range[i].nr_sectors)
263 : return true;
264 : }
265 :
266 : return false;
267 : }
268 :
269 : /**
270 : * disk_alloc_independent_access_ranges - Allocate an independent access ranges
271 : * data structure
272 : * @disk: target disk
273 : * @nr_ia_ranges: Number of independent access ranges
274 : *
275 : * Allocate a struct blk_independent_access_ranges structure with @nr_ia_ranges
276 : * access range descriptors.
277 : */
278 : struct blk_independent_access_ranges *
279 0 : disk_alloc_independent_access_ranges(struct gendisk *disk, int nr_ia_ranges)
280 : {
281 : struct blk_independent_access_ranges *iars;
282 :
283 0 : iars = kzalloc_node(struct_size(iars, ia_range, nr_ia_ranges),
284 0 : GFP_KERNEL, disk->queue->node);
285 0 : if (iars)
286 0 : iars->nr_ia_ranges = nr_ia_ranges;
287 0 : return iars;
288 : }
289 : EXPORT_SYMBOL_GPL(disk_alloc_independent_access_ranges);
290 :
291 : /**
292 : * disk_set_independent_access_ranges - Set a disk independent access ranges
293 : * @disk: target disk
294 : * @iars: independent access ranges structure
295 : *
296 : * Set the independent access ranges information of the request queue
297 : * of @disk to @iars. If @iars is NULL and the independent access ranges
298 : * structure already set is cleared. If there are no differences between
299 : * @iars and the independent access ranges structure already set, @iars
300 : * is freed.
301 : */
302 0 : void disk_set_independent_access_ranges(struct gendisk *disk,
303 : struct blk_independent_access_ranges *iars)
304 : {
305 0 : struct request_queue *q = disk->queue;
306 :
307 0 : if (WARN_ON_ONCE(iars && !iars->nr_ia_ranges)) {
308 0 : kfree(iars);
309 0 : iars = NULL;
310 : }
311 :
312 0 : mutex_lock(&q->sysfs_dir_lock);
313 0 : mutex_lock(&q->sysfs_lock);
314 :
315 0 : if (iars) {
316 0 : if (!disk_check_ia_ranges(disk, iars)) {
317 0 : kfree(iars);
318 0 : iars = NULL;
319 0 : goto reg;
320 : }
321 :
322 0 : if (!disk_ia_ranges_changed(disk, iars)) {
323 0 : kfree(iars);
324 0 : goto unlock;
325 : }
326 : }
327 :
328 : /*
329 : * This may be called for a registered queue. E.g. during a device
330 : * revalidation. If that is the case, we need to unregister the old
331 : * set of independent access ranges and register the new set. If the
332 : * queue is not registered, registration of the device request queue
333 : * will register the independent access ranges, so only swap in the
334 : * new set and free the old one.
335 : */
336 : reg:
337 0 : if (blk_queue_registered(q)) {
338 0 : disk_register_independent_access_ranges(disk, iars);
339 : } else {
340 0 : swap(q->ia_ranges, iars);
341 0 : kfree(iars);
342 : }
343 :
344 : unlock:
345 0 : mutex_unlock(&q->sysfs_lock);
346 0 : mutex_unlock(&q->sysfs_dir_lock);
347 0 : }
348 : EXPORT_SYMBOL_GPL(disk_set_independent_access_ranges);
|