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 :
58 0 : return entry->show(iar, buf);
59 : }
60 :
61 : static const struct sysfs_ops blk_ia_range_sysfs_ops = {
62 : .show = blk_ia_range_sysfs_show,
63 : };
64 :
65 : /*
66 : * Independent access range entries are not freed individually, but alltogether
67 : * with struct blk_independent_access_ranges and its array of ranges. Since
68 : * kobject_add() takes a reference on the parent kobject contained in
69 : * struct blk_independent_access_ranges, the array of independent access range
70 : * entries cannot be freed until kobject_del() is called for all entries.
71 : * So we do not need to do anything here, but still need this no-op release
72 : * operation to avoid complaints from the kobject code.
73 : */
74 0 : static void blk_ia_range_sysfs_nop_release(struct kobject *kobj)
75 : {
76 0 : }
77 :
78 : static const struct kobj_type blk_ia_range_ktype = {
79 : .sysfs_ops = &blk_ia_range_sysfs_ops,
80 : .default_groups = blk_ia_range_groups,
81 : .release = blk_ia_range_sysfs_nop_release,
82 : };
83 :
84 : /*
85 : * This will be executed only after all independent access range entries are
86 : * removed with kobject_del(), at which point, it is safe to free everything,
87 : * including the array of ranges.
88 : */
89 0 : static void blk_ia_ranges_sysfs_release(struct kobject *kobj)
90 : {
91 0 : struct blk_independent_access_ranges *iars =
92 0 : container_of(kobj, struct blk_independent_access_ranges, kobj);
93 :
94 0 : kfree(iars);
95 0 : }
96 :
97 : static const struct kobj_type blk_ia_ranges_ktype = {
98 : .release = blk_ia_ranges_sysfs_release,
99 : };
100 :
101 : /**
102 : * disk_register_independent_access_ranges - register with sysfs a set of
103 : * independent access ranges
104 : * @disk: Target disk
105 : *
106 : * Register with sysfs a set of independent access ranges for @disk.
107 : */
108 0 : int disk_register_independent_access_ranges(struct gendisk *disk)
109 : {
110 0 : struct blk_independent_access_ranges *iars = disk->ia_ranges;
111 0 : struct request_queue *q = disk->queue;
112 : int i, ret;
113 :
114 : lockdep_assert_held(&q->sysfs_dir_lock);
115 : lockdep_assert_held(&q->sysfs_lock);
116 :
117 0 : if (!iars)
118 : return 0;
119 :
120 : /*
121 : * At this point, iars is the new set of sector access ranges that needs
122 : * to be registered with sysfs.
123 : */
124 0 : WARN_ON(iars->sysfs_registered);
125 0 : ret = kobject_init_and_add(&iars->kobj, &blk_ia_ranges_ktype,
126 : &disk->queue_kobj, "%s",
127 : "independent_access_ranges");
128 0 : if (ret) {
129 0 : disk->ia_ranges = NULL;
130 0 : kobject_put(&iars->kobj);
131 0 : return ret;
132 : }
133 :
134 0 : for (i = 0; i < iars->nr_ia_ranges; i++) {
135 0 : ret = kobject_init_and_add(&iars->ia_range[i].kobj,
136 : &blk_ia_range_ktype, &iars->kobj,
137 : "%d", i);
138 0 : if (ret) {
139 0 : while (--i >= 0)
140 0 : kobject_del(&iars->ia_range[i].kobj);
141 0 : kobject_del(&iars->kobj);
142 0 : kobject_put(&iars->kobj);
143 0 : return ret;
144 : }
145 : }
146 :
147 0 : iars->sysfs_registered = true;
148 :
149 0 : return 0;
150 : }
151 :
152 0 : void disk_unregister_independent_access_ranges(struct gendisk *disk)
153 : {
154 0 : struct request_queue *q = disk->queue;
155 0 : struct blk_independent_access_ranges *iars = disk->ia_ranges;
156 : int i;
157 :
158 : lockdep_assert_held(&q->sysfs_dir_lock);
159 : lockdep_assert_held(&q->sysfs_lock);
160 :
161 0 : if (!iars)
162 : return;
163 :
164 0 : if (iars->sysfs_registered) {
165 0 : for (i = 0; i < iars->nr_ia_ranges; i++)
166 0 : kobject_del(&iars->ia_range[i].kobj);
167 0 : kobject_del(&iars->kobj);
168 0 : kobject_put(&iars->kobj);
169 : } else {
170 0 : kfree(iars);
171 : }
172 :
173 0 : disk->ia_ranges = NULL;
174 : }
175 :
176 : static struct blk_independent_access_range *
177 : disk_find_ia_range(struct blk_independent_access_ranges *iars,
178 : sector_t sector)
179 : {
180 : struct blk_independent_access_range *iar;
181 : int i;
182 :
183 0 : for (i = 0; i < iars->nr_ia_ranges; i++) {
184 0 : iar = &iars->ia_range[i];
185 0 : if (sector >= iar->sector &&
186 0 : sector < iar->sector + iar->nr_sectors)
187 : return iar;
188 : }
189 :
190 : return NULL;
191 : }
192 :
193 0 : static bool disk_check_ia_ranges(struct gendisk *disk,
194 : struct blk_independent_access_ranges *iars)
195 : {
196 : struct blk_independent_access_range *iar, *tmp;
197 0 : sector_t capacity = get_capacity(disk);
198 0 : sector_t sector = 0;
199 : int i;
200 :
201 0 : if (WARN_ON_ONCE(!iars->nr_ia_ranges))
202 : return false;
203 :
204 : /*
205 : * While sorting the ranges in increasing LBA order, check that the
206 : * ranges do not overlap, that there are no sector holes and that all
207 : * sectors belong to one range.
208 : */
209 0 : for (i = 0; i < iars->nr_ia_ranges; i++) {
210 0 : tmp = disk_find_ia_range(iars, sector);
211 0 : if (!tmp || tmp->sector != sector) {
212 0 : pr_warn("Invalid non-contiguous independent access ranges\n");
213 0 : return false;
214 : }
215 :
216 0 : iar = &iars->ia_range[i];
217 0 : if (tmp != iar) {
218 0 : swap(iar->sector, tmp->sector);
219 0 : swap(iar->nr_sectors, tmp->nr_sectors);
220 : }
221 :
222 0 : sector += iar->nr_sectors;
223 : }
224 :
225 0 : if (sector != capacity) {
226 0 : pr_warn("Independent access ranges do not match disk capacity\n");
227 0 : return false;
228 : }
229 :
230 : return true;
231 : }
232 :
233 : static bool disk_ia_ranges_changed(struct gendisk *disk,
234 : struct blk_independent_access_ranges *new)
235 : {
236 0 : struct blk_independent_access_ranges *old = disk->ia_ranges;
237 : int i;
238 :
239 0 : if (!old)
240 : return true;
241 :
242 0 : if (old->nr_ia_ranges != new->nr_ia_ranges)
243 : return true;
244 :
245 0 : for (i = 0; i < old->nr_ia_ranges; i++) {
246 0 : if (new->ia_range[i].sector != old->ia_range[i].sector ||
247 0 : new->ia_range[i].nr_sectors != old->ia_range[i].nr_sectors)
248 : return true;
249 : }
250 :
251 : return false;
252 : }
253 :
254 : /**
255 : * disk_alloc_independent_access_ranges - Allocate an independent access ranges
256 : * data structure
257 : * @disk: target disk
258 : * @nr_ia_ranges: Number of independent access ranges
259 : *
260 : * Allocate a struct blk_independent_access_ranges structure with @nr_ia_ranges
261 : * access range descriptors.
262 : */
263 : struct blk_independent_access_ranges *
264 0 : disk_alloc_independent_access_ranges(struct gendisk *disk, int nr_ia_ranges)
265 : {
266 : struct blk_independent_access_ranges *iars;
267 :
268 0 : iars = kzalloc_node(struct_size(iars, ia_range, nr_ia_ranges),
269 0 : GFP_KERNEL, disk->queue->node);
270 0 : if (iars)
271 0 : iars->nr_ia_ranges = nr_ia_ranges;
272 0 : return iars;
273 : }
274 : EXPORT_SYMBOL_GPL(disk_alloc_independent_access_ranges);
275 :
276 : /**
277 : * disk_set_independent_access_ranges - Set a disk independent access ranges
278 : * @disk: target disk
279 : * @iars: independent access ranges structure
280 : *
281 : * Set the independent access ranges information of the request queue
282 : * of @disk to @iars. If @iars is NULL and the independent access ranges
283 : * structure already set is cleared. If there are no differences between
284 : * @iars and the independent access ranges structure already set, @iars
285 : * is freed.
286 : */
287 0 : void disk_set_independent_access_ranges(struct gendisk *disk,
288 : struct blk_independent_access_ranges *iars)
289 : {
290 0 : struct request_queue *q = disk->queue;
291 :
292 0 : mutex_lock(&q->sysfs_dir_lock);
293 0 : mutex_lock(&q->sysfs_lock);
294 0 : if (iars && !disk_check_ia_ranges(disk, iars)) {
295 0 : kfree(iars);
296 0 : iars = NULL;
297 : }
298 0 : if (iars && !disk_ia_ranges_changed(disk, iars)) {
299 0 : kfree(iars);
300 0 : goto unlock;
301 : }
302 :
303 : /*
304 : * This may be called for a registered queue. E.g. during a device
305 : * revalidation. If that is the case, we need to unregister the old
306 : * set of independent access ranges and register the new set. If the
307 : * queue is not registered, registration of the device request queue
308 : * will register the independent access ranges.
309 : */
310 0 : disk_unregister_independent_access_ranges(disk);
311 0 : disk->ia_ranges = iars;
312 0 : if (blk_queue_registered(q))
313 0 : disk_register_independent_access_ranges(disk);
314 : unlock:
315 0 : mutex_unlock(&q->sysfs_lock);
316 0 : mutex_unlock(&q->sysfs_dir_lock);
317 0 : }
318 : EXPORT_SYMBOL_GPL(disk_set_independent_access_ranges);
|