2 * Copyright (c) 2014 Christoph Hellwig.
4 #include <linux/sunrpc/svc.h>
5 #include <linux/blkdev.h>
6 #include <linux/nfs4.h>
7 #include <linux/nfs_fs.h>
8 #include <linux/nfs_xdr.h>
10 #include "blocklayout.h"
12 #define NFSDBG_FACILITY NFSDBG_PNFS_LD
15 bl_free_device(struct pnfs_block_dev
*dev
)
17 if (dev
->nr_children
) {
20 for (i
= 0; i
< dev
->nr_children
; i
++)
21 bl_free_device(&dev
->children
[i
]);
25 blkdev_put(dev
->bdev
, FMODE_READ
);
30 bl_free_deviceid_node(struct nfs4_deviceid_node
*d
)
32 struct pnfs_block_dev
*dev
=
33 container_of(d
, struct pnfs_block_dev
, node
);
40 nfs4_block_decode_volume(struct xdr_stream
*xdr
, struct pnfs_block_volume
*b
)
45 p
= xdr_inline_decode(xdr
, 4);
48 b
->type
= be32_to_cpup(p
++);
51 case PNFS_BLOCK_VOLUME_SIMPLE
:
52 p
= xdr_inline_decode(xdr
, 4);
55 b
->simple
.nr_sigs
= be32_to_cpup(p
++);
56 if (!b
->simple
.nr_sigs
) {
57 dprintk("no signature\n");
61 b
->simple
.len
= 4 + 4;
62 for (i
= 0; i
< b
->simple
.nr_sigs
; i
++) {
63 p
= xdr_inline_decode(xdr
, 8 + 4);
66 p
= xdr_decode_hyper(p
, &b
->simple
.sigs
[i
].offset
);
67 b
->simple
.sigs
[i
].sig_len
= be32_to_cpup(p
++);
69 p
= xdr_inline_decode(xdr
, b
->simple
.sigs
[i
].sig_len
);
72 memcpy(&b
->simple
.sigs
[i
].sig
, p
,
73 b
->simple
.sigs
[i
].sig_len
);
75 b
->simple
.len
+= 8 + 4 + b
->simple
.sigs
[i
].sig_len
;
78 case PNFS_BLOCK_VOLUME_SLICE
:
79 p
= xdr_inline_decode(xdr
, 8 + 8 + 4);
82 p
= xdr_decode_hyper(p
, &b
->slice
.start
);
83 p
= xdr_decode_hyper(p
, &b
->slice
.len
);
84 b
->slice
.volume
= be32_to_cpup(p
++);
86 case PNFS_BLOCK_VOLUME_CONCAT
:
87 p
= xdr_inline_decode(xdr
, 4);
90 b
->concat
.volumes_count
= be32_to_cpup(p
++);
92 p
= xdr_inline_decode(xdr
, b
->concat
.volumes_count
* 4);
95 for (i
= 0; i
< b
->concat
.volumes_count
; i
++)
96 b
->concat
.volumes
[i
] = be32_to_cpup(p
++);
98 case PNFS_BLOCK_VOLUME_STRIPE
:
99 p
= xdr_inline_decode(xdr
, 8 + 4);
102 p
= xdr_decode_hyper(p
, &b
->stripe
.chunk_size
);
103 b
->stripe
.volumes_count
= be32_to_cpup(p
++);
105 p
= xdr_inline_decode(xdr
, b
->stripe
.volumes_count
* 4);
108 for (i
= 0; i
< b
->stripe
.volumes_count
; i
++)
109 b
->stripe
.volumes
[i
] = be32_to_cpup(p
++);
112 dprintk("unknown volume type!\n");
119 static bool bl_map_simple(struct pnfs_block_dev
*dev
, u64 offset
,
120 struct pnfs_block_dev_map
*map
)
122 map
->start
= dev
->start
;
124 map
->disk_offset
= dev
->disk_offset
;
125 map
->bdev
= dev
->bdev
;
129 static bool bl_map_concat(struct pnfs_block_dev
*dev
, u64 offset
,
130 struct pnfs_block_dev_map
*map
)
134 for (i
= 0; i
< dev
->nr_children
; i
++) {
135 struct pnfs_block_dev
*child
= &dev
->children
[i
];
137 if (child
->start
> offset
||
138 child
->start
+ child
->len
<= offset
)
141 child
->map(child
, offset
- child
->start
, map
);
145 dprintk("%s: ran off loop!\n", __func__
);
149 static bool bl_map_stripe(struct pnfs_block_dev
*dev
, u64 offset
,
150 struct pnfs_block_dev_map
*map
)
152 struct pnfs_block_dev
*child
;
157 chunk
= div_u64(offset
, dev
->chunk_size
);
158 div_u64_rem(chunk
, dev
->nr_children
, &chunk_idx
);
160 if (chunk_idx
> dev
->nr_children
) {
161 dprintk("%s: invalid chunk idx %d (%lld/%lld)\n",
162 __func__
, chunk_idx
, offset
, dev
->chunk_size
);
163 /* error, should not happen */
167 /* truncate offset to the beginning of the stripe */
168 offset
= chunk
* dev
->chunk_size
;
170 /* disk offset of the stripe */
171 disk_offset
= div_u64(offset
, dev
->nr_children
);
173 child
= &dev
->children
[chunk_idx
];
174 child
->map(child
, disk_offset
, map
);
176 map
->start
+= offset
;
177 map
->disk_offset
+= disk_offset
;
178 map
->len
= dev
->chunk_size
;
183 bl_parse_deviceid(struct nfs_server
*server
, struct pnfs_block_dev
*d
,
184 struct pnfs_block_volume
*volumes
, int idx
, gfp_t gfp_mask
);
188 bl_parse_simple(struct nfs_server
*server
, struct pnfs_block_dev
*d
,
189 struct pnfs_block_volume
*volumes
, int idx
, gfp_t gfp_mask
)
191 struct pnfs_block_volume
*v
= &volumes
[idx
];
194 dev
= bl_resolve_deviceid(server
, v
, gfp_mask
);
198 d
->bdev
= blkdev_get_by_dev(dev
, FMODE_READ
, NULL
);
199 if (IS_ERR(d
->bdev
)) {
200 printk(KERN_WARNING
"pNFS: failed to open device %d:%d (%ld)\n",
201 MAJOR(dev
), MINOR(dev
), PTR_ERR(d
->bdev
));
202 return PTR_ERR(d
->bdev
);
206 d
->len
= i_size_read(d
->bdev
->bd_inode
);
207 d
->map
= bl_map_simple
;
209 printk(KERN_INFO
"pNFS: using block device %s\n",
210 d
->bdev
->bd_disk
->disk_name
);
215 bl_parse_slice(struct nfs_server
*server
, struct pnfs_block_dev
*d
,
216 struct pnfs_block_volume
*volumes
, int idx
, gfp_t gfp_mask
)
218 struct pnfs_block_volume
*v
= &volumes
[idx
];
221 ret
= bl_parse_deviceid(server
, d
, volumes
, v
->slice
.volume
, gfp_mask
);
225 d
->disk_offset
= v
->slice
.start
;
226 d
->len
= v
->slice
.len
;
231 bl_parse_concat(struct nfs_server
*server
, struct pnfs_block_dev
*d
,
232 struct pnfs_block_volume
*volumes
, int idx
, gfp_t gfp_mask
)
234 struct pnfs_block_volume
*v
= &volumes
[idx
];
238 d
->children
= kcalloc(v
->concat
.volumes_count
,
239 sizeof(struct pnfs_block_dev
), GFP_KERNEL
);
243 for (i
= 0; i
< v
->concat
.volumes_count
; i
++) {
244 ret
= bl_parse_deviceid(server
, &d
->children
[i
],
245 volumes
, v
->concat
.volumes
[i
], gfp_mask
);
250 d
->children
[i
].start
+= len
;
251 len
+= d
->children
[i
].len
;
255 d
->map
= bl_map_concat
;
260 bl_parse_stripe(struct nfs_server
*server
, struct pnfs_block_dev
*d
,
261 struct pnfs_block_volume
*volumes
, int idx
, gfp_t gfp_mask
)
263 struct pnfs_block_volume
*v
= &volumes
[idx
];
267 d
->children
= kcalloc(v
->stripe
.volumes_count
,
268 sizeof(struct pnfs_block_dev
), GFP_KERNEL
);
272 for (i
= 0; i
< v
->stripe
.volumes_count
; i
++) {
273 ret
= bl_parse_deviceid(server
, &d
->children
[i
],
274 volumes
, v
->stripe
.volumes
[i
], gfp_mask
);
279 len
+= d
->children
[i
].len
;
283 d
->chunk_size
= v
->stripe
.chunk_size
;
284 d
->map
= bl_map_stripe
;
289 bl_parse_deviceid(struct nfs_server
*server
, struct pnfs_block_dev
*d
,
290 struct pnfs_block_volume
*volumes
, int idx
, gfp_t gfp_mask
)
292 switch (volumes
[idx
].type
) {
293 case PNFS_BLOCK_VOLUME_SIMPLE
:
294 return bl_parse_simple(server
, d
, volumes
, idx
, gfp_mask
);
295 case PNFS_BLOCK_VOLUME_SLICE
:
296 return bl_parse_slice(server
, d
, volumes
, idx
, gfp_mask
);
297 case PNFS_BLOCK_VOLUME_CONCAT
:
298 return bl_parse_concat(server
, d
, volumes
, idx
, gfp_mask
);
299 case PNFS_BLOCK_VOLUME_STRIPE
:
300 return bl_parse_stripe(server
, d
, volumes
, idx
, gfp_mask
);
302 dprintk("unsupported volume type: %d\n", volumes
[idx
].type
);
307 struct nfs4_deviceid_node
*
308 bl_alloc_deviceid_node(struct nfs_server
*server
, struct pnfs_device
*pdev
,
311 struct nfs4_deviceid_node
*node
= NULL
;
312 struct pnfs_block_volume
*volumes
;
313 struct pnfs_block_dev
*top
;
314 struct xdr_stream xdr
;
316 struct page
*scratch
;
317 int nr_volumes
, ret
, i
;
320 scratch
= alloc_page(gfp_mask
);
324 xdr_init_decode_pages(&xdr
, &buf
, pdev
->pages
, pdev
->pglen
);
325 xdr_set_scratch_buffer(&xdr
, page_address(scratch
), PAGE_SIZE
);
327 p
= xdr_inline_decode(&xdr
, sizeof(__be32
));
329 goto out_free_scratch
;
330 nr_volumes
= be32_to_cpup(p
++);
332 volumes
= kcalloc(nr_volumes
, sizeof(struct pnfs_block_volume
),
335 goto out_free_scratch
;
337 for (i
= 0; i
< nr_volumes
; i
++) {
338 ret
= nfs4_block_decode_volume(&xdr
, &volumes
[i
]);
340 goto out_free_volumes
;
343 top
= kzalloc(sizeof(*top
), gfp_mask
);
345 goto out_free_volumes
;
347 ret
= bl_parse_deviceid(server
, top
, volumes
, nr_volumes
- 1, gfp_mask
);
351 goto out_free_volumes
;
355 nfs4_init_deviceid_node(node
, server
, &pdev
->dev_id
);
360 __free_page(scratch
);