@@ -92,41 +92,54 @@ static int compat_blkpg_ioctl(struct block_device *bdev,
9292}
9393#endif
9494
95+ /*
96+ * Check that [start, start + len) is a valid range from the block device's
97+ * perspective, including verifying that it can be correctly translated into
98+ * logical block addresses.
99+ */
100+ static int blk_validate_byte_range (struct block_device * bdev ,
101+ uint64_t start , uint64_t len )
102+ {
103+ unsigned int bs_mask = bdev_logical_block_size (bdev ) - 1 ;
104+ uint64_t end ;
105+
106+ if ((start | len ) & bs_mask )
107+ return - EINVAL ;
108+ if (!len )
109+ return - EINVAL ;
110+ if (check_add_overflow (start , len , & end ) || end > bdev_nr_bytes (bdev ))
111+ return - EINVAL ;
112+
113+ return 0 ;
114+ }
115+
95116static int blk_ioctl_discard (struct block_device * bdev , blk_mode_t mode ,
96117 unsigned long arg )
97118{
98- unsigned int bs_mask = bdev_logical_block_size (bdev ) - 1 ;
99- uint64_t range [2 ], start , len , end ;
119+ uint64_t range [2 ], start , len ;
100120 struct bio * prev = NULL , * bio ;
101121 sector_t sector , nr_sects ;
102122 struct blk_plug plug ;
103123 int err ;
104124
105- if (!(mode & BLK_OPEN_WRITE ))
106- return - EBADF ;
107-
108- if (!bdev_max_discard_sectors (bdev ))
109- return - EOPNOTSUPP ;
110- if (bdev_read_only (bdev ))
111- return - EPERM ;
112-
113125 if (copy_from_user (range , (void __user * )arg , sizeof (range )))
114126 return - EFAULT ;
115-
116127 start = range [0 ];
117128 len = range [1 ];
118129
119- if (!len )
120- return - EINVAL ;
121- if ((start | len ) & bs_mask )
122- return - EINVAL ;
130+ if (!bdev_max_discard_sectors (bdev ))
131+ return - EOPNOTSUPP ;
123132
124- if (check_add_overflow (start , len , & end ) ||
125- end > bdev_nr_bytes (bdev ))
126- return - EINVAL ;
133+ if (!(mode & BLK_OPEN_WRITE ))
134+ return - EBADF ;
135+ if (bdev_read_only (bdev ))
136+ return - EPERM ;
137+ err = blk_validate_byte_range (bdev , start , len );
138+ if (err )
139+ return err ;
127140
128141 filemap_invalidate_lock (bdev -> bd_mapping );
129- err = truncate_bdev_range (bdev , mode , start , end - 1 );
142+ err = truncate_bdev_range (bdev , mode , start , start + len - 1 );
130143 if (err )
131144 goto fail ;
132145
0 commit comments