diff options
Diffstat (limited to 'fs/nfs/blocklayout/dev.c')
-rw-r--r-- | fs/nfs/blocklayout/dev.c | 144 |
1 files changed, 143 insertions, 1 deletions
diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c index a861bbdfe577..e5b89675263e 100644 --- a/fs/nfs/blocklayout/dev.c +++ b/fs/nfs/blocklayout/dev.c | |||
@@ -1,11 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2014 Christoph Hellwig. | 2 | * Copyright (c) 2014-2016 Christoph Hellwig. |
3 | */ | 3 | */ |
4 | #include <linux/sunrpc/svc.h> | 4 | #include <linux/sunrpc/svc.h> |
5 | #include <linux/blkdev.h> | 5 | #include <linux/blkdev.h> |
6 | #include <linux/nfs4.h> | 6 | #include <linux/nfs4.h> |
7 | #include <linux/nfs_fs.h> | 7 | #include <linux/nfs_fs.h> |
8 | #include <linux/nfs_xdr.h> | 8 | #include <linux/nfs_xdr.h> |
9 | #include <linux/pr.h> | ||
9 | 10 | ||
10 | #include "blocklayout.h" | 11 | #include "blocklayout.h" |
11 | 12 | ||
@@ -21,6 +22,17 @@ bl_free_device(struct pnfs_block_dev *dev) | |||
21 | bl_free_device(&dev->children[i]); | 22 | bl_free_device(&dev->children[i]); |
22 | kfree(dev->children); | 23 | kfree(dev->children); |
23 | } else { | 24 | } else { |
25 | if (dev->pr_registered) { | ||
26 | const struct pr_ops *ops = | ||
27 | dev->bdev->bd_disk->fops->pr_ops; | ||
28 | int error; | ||
29 | |||
30 | error = ops->pr_register(dev->bdev, dev->pr_key, 0, | ||
31 | false); | ||
32 | if (error) | ||
33 | pr_err("failed to unregister PR key.\n"); | ||
34 | } | ||
35 | |||
24 | if (dev->bdev) | 36 | if (dev->bdev) |
25 | blkdev_put(dev->bdev, FMODE_READ | FMODE_WRITE); | 37 | blkdev_put(dev->bdev, FMODE_READ | FMODE_WRITE); |
26 | } | 38 | } |
@@ -113,6 +125,24 @@ nfs4_block_decode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b) | |||
113 | for (i = 0; i < b->stripe.volumes_count; i++) | 125 | for (i = 0; i < b->stripe.volumes_count; i++) |
114 | b->stripe.volumes[i] = be32_to_cpup(p++); | 126 | b->stripe.volumes[i] = be32_to_cpup(p++); |
115 | break; | 127 | break; |
128 | case PNFS_BLOCK_VOLUME_SCSI: | ||
129 | p = xdr_inline_decode(xdr, 4 + 4 + 4); | ||
130 | if (!p) | ||
131 | return -EIO; | ||
132 | b->scsi.code_set = be32_to_cpup(p++); | ||
133 | b->scsi.designator_type = be32_to_cpup(p++); | ||
134 | b->scsi.designator_len = be32_to_cpup(p++); | ||
135 | p = xdr_inline_decode(xdr, b->scsi.designator_len); | ||
136 | if (!p) | ||
137 | return -EIO; | ||
138 | if (b->scsi.designator_len > 256) | ||
139 | return -EIO; | ||
140 | memcpy(&b->scsi.designator, p, b->scsi.designator_len); | ||
141 | p = xdr_inline_decode(xdr, 8); | ||
142 | if (!p) | ||
143 | return -EIO; | ||
144 | p = xdr_decode_hyper(p, &b->scsi.pr_key); | ||
145 | break; | ||
116 | default: | 146 | default: |
117 | dprintk("unknown volume type!\n"); | 147 | dprintk("unknown volume type!\n"); |
118 | return -EIO; | 148 | return -EIO; |
@@ -216,6 +246,116 @@ bl_parse_simple(struct nfs_server *server, struct pnfs_block_dev *d, | |||
216 | return 0; | 246 | return 0; |
217 | } | 247 | } |
218 | 248 | ||
249 | static bool | ||
250 | bl_validate_designator(struct pnfs_block_volume *v) | ||
251 | { | ||
252 | switch (v->scsi.designator_type) { | ||
253 | case PS_DESIGNATOR_EUI64: | ||
254 | if (v->scsi.code_set != PS_CODE_SET_BINARY) | ||
255 | return false; | ||
256 | |||
257 | if (v->scsi.designator_len != 8 && | ||
258 | v->scsi.designator_len != 10 && | ||
259 | v->scsi.designator_len != 16) | ||
260 | return false; | ||
261 | |||
262 | return true; | ||
263 | case PS_DESIGNATOR_NAA: | ||
264 | if (v->scsi.code_set != PS_CODE_SET_BINARY) | ||
265 | return false; | ||
266 | |||
267 | if (v->scsi.designator_len != 8 && | ||
268 | v->scsi.designator_len != 16) | ||
269 | return false; | ||
270 | |||
271 | return true; | ||
272 | case PS_DESIGNATOR_T10: | ||
273 | case PS_DESIGNATOR_NAME: | ||
274 | pr_err("pNFS: unsupported designator " | ||
275 | "(code set %d, type %d, len %d.\n", | ||
276 | v->scsi.code_set, | ||
277 | v->scsi.designator_type, | ||
278 | v->scsi.designator_len); | ||
279 | return false; | ||
280 | default: | ||
281 | pr_err("pNFS: invalid designator " | ||
282 | "(code set %d, type %d, len %d.\n", | ||
283 | v->scsi.code_set, | ||
284 | v->scsi.designator_type, | ||
285 | v->scsi.designator_len); | ||
286 | return false; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | static int | ||
291 | bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d, | ||
292 | struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask) | ||
293 | { | ||
294 | struct pnfs_block_volume *v = &volumes[idx]; | ||
295 | const struct pr_ops *ops; | ||
296 | const char *devname; | ||
297 | int error; | ||
298 | |||
299 | if (!bl_validate_designator(v)) | ||
300 | return -EINVAL; | ||
301 | |||
302 | switch (v->scsi.designator_len) { | ||
303 | case 8: | ||
304 | devname = kasprintf(GFP_KERNEL, "/dev/disk/by-id/wwn-0x%8phN", | ||
305 | v->scsi.designator); | ||
306 | break; | ||
307 | case 12: | ||
308 | devname = kasprintf(GFP_KERNEL, "/dev/disk/by-id/wwn-0x%12phN", | ||
309 | v->scsi.designator); | ||
310 | break; | ||
311 | case 16: | ||
312 | devname = kasprintf(GFP_KERNEL, "/dev/disk/by-id/wwn-0x%16phN", | ||
313 | v->scsi.designator); | ||
314 | break; | ||
315 | default: | ||
316 | return -EINVAL; | ||
317 | } | ||
318 | |||
319 | d->bdev = blkdev_get_by_path(devname, FMODE_READ, NULL); | ||
320 | if (IS_ERR(d->bdev)) { | ||
321 | pr_warn("pNFS: failed to open device %s (%ld)\n", | ||
322 | devname, PTR_ERR(d->bdev)); | ||
323 | kfree(devname); | ||
324 | return PTR_ERR(d->bdev); | ||
325 | } | ||
326 | |||
327 | kfree(devname); | ||
328 | |||
329 | d->len = i_size_read(d->bdev->bd_inode); | ||
330 | d->map = bl_map_simple; | ||
331 | d->pr_key = v->scsi.pr_key; | ||
332 | |||
333 | pr_info("pNFS: using block device %s (reservation key 0x%llx)\n", | ||
334 | d->bdev->bd_disk->disk_name, d->pr_key); | ||
335 | |||
336 | ops = d->bdev->bd_disk->fops->pr_ops; | ||
337 | if (!ops) { | ||
338 | pr_err("pNFS: block device %s does not support reservations.", | ||
339 | d->bdev->bd_disk->disk_name); | ||
340 | error = -EINVAL; | ||
341 | goto out_blkdev_put; | ||
342 | } | ||
343 | |||
344 | error = ops->pr_register(d->bdev, 0, d->pr_key, true); | ||
345 | if (error) { | ||
346 | pr_err("pNFS: failed to register key for block device %s.", | ||
347 | d->bdev->bd_disk->disk_name); | ||
348 | goto out_blkdev_put; | ||
349 | } | ||
350 | |||
351 | d->pr_registered = true; | ||
352 | return 0; | ||
353 | |||
354 | out_blkdev_put: | ||
355 | blkdev_put(d->bdev, FMODE_READ); | ||
356 | return error; | ||
357 | } | ||
358 | |||
219 | static int | 359 | static int |
220 | bl_parse_slice(struct nfs_server *server, struct pnfs_block_dev *d, | 360 | bl_parse_slice(struct nfs_server *server, struct pnfs_block_dev *d, |
221 | struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask) | 361 | struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask) |
@@ -303,6 +443,8 @@ bl_parse_deviceid(struct nfs_server *server, struct pnfs_block_dev *d, | |||
303 | return bl_parse_concat(server, d, volumes, idx, gfp_mask); | 443 | return bl_parse_concat(server, d, volumes, idx, gfp_mask); |
304 | case PNFS_BLOCK_VOLUME_STRIPE: | 444 | case PNFS_BLOCK_VOLUME_STRIPE: |
305 | return bl_parse_stripe(server, d, volumes, idx, gfp_mask); | 445 | return bl_parse_stripe(server, d, volumes, idx, gfp_mask); |
446 | case PNFS_BLOCK_VOLUME_SCSI: | ||
447 | return bl_parse_scsi(server, d, volumes, idx, gfp_mask); | ||
306 | default: | 448 | default: |
307 | dprintk("unsupported volume type: %d\n", volumes[idx].type); | 449 | dprintk("unsupported volume type: %d\n", volumes[idx].type); |
308 | return -EIO; | 450 | return -EIO; |