@@ -65,8 +65,8 @@ nfs4_block_decode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
6565 if (!p )
6666 return - EIO ;
6767 b -> simple .nr_sigs = be32_to_cpup (p ++ );
68- if (!b -> simple .nr_sigs ) {
69- dprintk ("no signature\n" );
68+ if (!b -> simple .nr_sigs || b -> simple . nr_sigs > PNFS_BLOCK_MAX_UUIDS ) {
69+ dprintk ("Bad signature count: %d \n" , b -> simple . nr_sigs );
7070 return - EIO ;
7171 }
7272
@@ -89,7 +89,8 @@ nfs4_block_decode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
8989 memcpy (& b -> simple .sigs [i ].sig , p ,
9090 b -> simple .sigs [i ].sig_len );
9191
92- b -> simple .len += 8 + 4 + b -> simple .sigs [i ].sig_len ;
92+ b -> simple .len += 8 + 4 + \
93+ (XDR_QUADLEN (b -> simple .sigs [i ].sig_len ) << 2 );
9394 }
9495 break ;
9596 case PNFS_BLOCK_VOLUME_SLICE :
@@ -104,7 +105,12 @@ nfs4_block_decode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
104105 p = xdr_inline_decode (xdr , 4 );
105106 if (!p )
106107 return - EIO ;
108+
107109 b -> concat .volumes_count = be32_to_cpup (p ++ );
110+ if (b -> concat .volumes_count > PNFS_BLOCK_MAX_DEVICES ) {
111+ dprintk ("Too many volumes: %d\n" , b -> concat .volumes_count );
112+ return - EIO ;
113+ }
108114
109115 p = xdr_inline_decode (xdr , b -> concat .volumes_count * 4 );
110116 if (!p )
@@ -116,8 +122,13 @@ nfs4_block_decode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
116122 p = xdr_inline_decode (xdr , 8 + 4 );
117123 if (!p )
118124 return - EIO ;
125+
119126 p = xdr_decode_hyper (p , & b -> stripe .chunk_size );
120127 b -> stripe .volumes_count = be32_to_cpup (p ++ );
128+ if (b -> stripe .volumes_count > PNFS_BLOCK_MAX_DEVICES ) {
129+ dprintk ("Too many volumes: %d\n" , b -> stripe .volumes_count );
130+ return - EIO ;
131+ }
121132
122133 p = xdr_inline_decode (xdr , b -> stripe .volumes_count * 4 );
123134 if (!p )
@@ -224,18 +235,20 @@ bl_parse_simple(struct nfs_server *server, struct pnfs_block_dev *d,
224235 struct pnfs_block_volume * volumes , int idx , gfp_t gfp_mask )
225236{
226237 struct pnfs_block_volume * v = & volumes [idx ];
238+ struct block_device * bdev ;
227239 dev_t dev ;
228240
229241 dev = bl_resolve_deviceid (server , v , gfp_mask );
230242 if (!dev )
231243 return - EIO ;
232244
233- d -> bdev = blkdev_get_by_dev (dev , FMODE_READ | FMODE_WRITE , NULL );
234- if (IS_ERR (d -> bdev )) {
245+ bdev = blkdev_get_by_dev (dev , FMODE_READ | FMODE_WRITE , NULL );
246+ if (IS_ERR (bdev )) {
235247 printk (KERN_WARNING "pNFS: failed to open device %d:%d (%ld)\n" ,
236- MAJOR (dev ), MINOR (dev ), PTR_ERR (d -> bdev ));
237- return PTR_ERR (d -> bdev );
248+ MAJOR (dev ), MINOR (dev ), PTR_ERR (bdev ));
249+ return PTR_ERR (bdev );
238250 }
251+ d -> bdev = bdev ;
239252
240253
241254 d -> len = i_size_read (d -> bdev -> bd_inode );
@@ -287,44 +300,71 @@ bl_validate_designator(struct pnfs_block_volume *v)
287300 }
288301}
289302
303+ /*
304+ * Try to open the udev path for the WWN. At least on Debian the udev
305+ * by-id path will always point to the dm-multipath device if one exists.
306+ */
307+ static struct block_device *
308+ bl_open_udev_path (struct pnfs_block_volume * v )
309+ {
310+ struct block_device * bdev ;
311+ const char * devname ;
312+
313+ devname = kasprintf (GFP_KERNEL , "/dev/disk/by-id/wwn-0x%*phN" ,
314+ v -> scsi .designator_len , v -> scsi .designator );
315+ if (!devname )
316+ return ERR_PTR (- ENOMEM );
317+
318+ bdev = blkdev_get_by_path (devname , FMODE_READ | FMODE_WRITE , NULL );
319+ if (IS_ERR (bdev )) {
320+ pr_warn ("pNFS: failed to open device %s (%ld)\n" ,
321+ devname , PTR_ERR (bdev ));
322+ }
323+
324+ kfree (devname );
325+ return bdev ;
326+ }
327+
328+ /*
329+ * Try to open the RH/Fedora specific dm-mpath udev path for this WWN, as the
330+ * wwn- links will only point to the first discovered SCSI device there.
331+ */
332+ static struct block_device *
333+ bl_open_dm_mpath_udev_path (struct pnfs_block_volume * v )
334+ {
335+ struct block_device * bdev ;
336+ const char * devname ;
337+
338+ devname = kasprintf (GFP_KERNEL ,
339+ "/dev/disk/by-id/dm-uuid-mpath-%d%*phN" ,
340+ v -> scsi .designator_type ,
341+ v -> scsi .designator_len , v -> scsi .designator );
342+ if (!devname )
343+ return ERR_PTR (- ENOMEM );
344+
345+ bdev = blkdev_get_by_path (devname , FMODE_READ | FMODE_WRITE , NULL );
346+ kfree (devname );
347+ return bdev ;
348+ }
349+
290350static int
291351bl_parse_scsi (struct nfs_server * server , struct pnfs_block_dev * d ,
292352 struct pnfs_block_volume * volumes , int idx , gfp_t gfp_mask )
293353{
294354 struct pnfs_block_volume * v = & volumes [idx ];
355+ struct block_device * bdev ;
295356 const struct pr_ops * ops ;
296- const char * devname ;
297357 int error ;
298358
299359 if (!bl_validate_designator (v ))
300360 return - EINVAL ;
301361
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 );
362+ bdev = bl_open_dm_mpath_udev_path (v );
363+ if (IS_ERR (bdev ))
364+ bdev = bl_open_udev_path (v );
365+ if (IS_ERR (bdev ))
366+ return PTR_ERR (bdev );
367+ d -> bdev = bdev ;
328368
329369 d -> len = i_size_read (d -> bdev -> bd_inode );
330370 d -> map = bl_map_simple ;
@@ -352,7 +392,7 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d,
352392 return 0 ;
353393
354394out_blkdev_put :
355- blkdev_put (d -> bdev , FMODE_READ );
395+ blkdev_put (d -> bdev , FMODE_READ | FMODE_WRITE );
356396 return error ;
357397}
358398
0 commit comments