aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/blocklayout/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/blocklayout/dev.c')
-rw-r--r--fs/nfs/blocklayout/dev.c144
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
249static bool
250bl_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
290static int
291bl_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
354out_blkdev_put:
355 blkdev_put(d->bdev, FMODE_READ);
356 return error;
357}
358
219static int 359static int
220bl_parse_slice(struct nfs_server *server, struct pnfs_block_dev *d, 360bl_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;