aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/compat_ioctl.c1
-rw-r--r--block/ioctl.c76
-rw-r--r--include/linux/fs.h1
3 files changed, 78 insertions, 0 deletions
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index c23177e4623f..1e559fba7bdf 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -788,6 +788,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
788 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg)); 788 return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
789 case BLKFLSBUF: 789 case BLKFLSBUF:
790 case BLKROSET: 790 case BLKROSET:
791 case BLKDISCARD:
791 /* 792 /*
792 * the ones below are implemented in blkdev_locked_ioctl, 793 * the ones below are implemented in blkdev_locked_ioctl,
793 * but we call blkdev_ioctl, which gets the lock for us 794 * but we call blkdev_ioctl, which gets the lock for us
diff --git a/block/ioctl.c b/block/ioctl.c
index 77185e5c026a..342298bb6080 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -111,6 +111,69 @@ static int blkdev_reread_part(struct block_device *bdev)
111 return res; 111 return res;
112} 112}
113 113
114static void blk_ioc_discard_endio(struct bio *bio, int err)
115{
116 if (err) {
117 if (err == -EOPNOTSUPP)
118 set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
119 clear_bit(BIO_UPTODATE, &bio->bi_flags);
120 }
121 complete(bio->bi_private);
122}
123
124static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
125 uint64_t len)
126{
127 struct request_queue *q = bdev_get_queue(bdev);
128 int ret = 0;
129
130 if (start & 511)
131 return -EINVAL;
132 if (len & 511)
133 return -EINVAL;
134 start >>= 9;
135 len >>= 9;
136
137 if (start + len > (bdev->bd_inode->i_size >> 9))
138 return -EINVAL;
139
140 if (!q->prepare_discard_fn)
141 return -EOPNOTSUPP;
142
143 while (len && !ret) {
144 DECLARE_COMPLETION_ONSTACK(wait);
145 struct bio *bio;
146
147 bio = bio_alloc(GFP_KERNEL, 0);
148 if (!bio)
149 return -ENOMEM;
150
151 bio->bi_end_io = blk_ioc_discard_endio;
152 bio->bi_bdev = bdev;
153 bio->bi_private = &wait;
154 bio->bi_sector = start;
155
156 if (len > q->max_hw_sectors) {
157 bio->bi_size = q->max_hw_sectors << 9;
158 len -= q->max_hw_sectors;
159 start += q->max_hw_sectors;
160 } else {
161 bio->bi_size = len << 9;
162 len = 0;
163 }
164 submit_bio(WRITE_DISCARD, bio);
165
166 wait_for_completion(&wait);
167
168 if (bio_flagged(bio, BIO_EOPNOTSUPP))
169 ret = -EOPNOTSUPP;
170 else if (!bio_flagged(bio, BIO_UPTODATE))
171 ret = -EIO;
172 bio_put(bio);
173 }
174 return ret;
175}
176
114static int put_ushort(unsigned long arg, unsigned short val) 177static int put_ushort(unsigned long arg, unsigned short val)
115{ 178{
116 return put_user(val, (unsigned short __user *)arg); 179 return put_user(val, (unsigned short __user *)arg);
@@ -258,6 +321,19 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
258 set_device_ro(bdev, n); 321 set_device_ro(bdev, n);
259 unlock_kernel(); 322 unlock_kernel();
260 return 0; 323 return 0;
324
325 case BLKDISCARD: {
326 uint64_t range[2];
327
328 if (!(file->f_mode & FMODE_WRITE))
329 return -EBADF;
330
331 if (copy_from_user(range, (void __user *)arg, sizeof(range)))
332 return -EFAULT;
333
334 return blk_ioctl_discard(bdev, range[0], range[1]);
335 }
336
261 case HDIO_GETGEO: { 337 case HDIO_GETGEO: {
262 struct hd_geometry geo; 338 struct hd_geometry geo;
263 339
diff --git a/include/linux/fs.h b/include/linux/fs.h
index eb0131319134..88358ca6af25 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -223,6 +223,7 @@ extern int dir_notify_enable;
223#define BLKTRACESTART _IO(0x12,116) 223#define BLKTRACESTART _IO(0x12,116)
224#define BLKTRACESTOP _IO(0x12,117) 224#define BLKTRACESTOP _IO(0x12,117)
225#define BLKTRACETEARDOWN _IO(0x12,118) 225#define BLKTRACETEARDOWN _IO(0x12,118)
226#define BLKDISCARD _IO(0x12,119)
226 227
227#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ 228#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
228#define FIBMAP _IO(0x00,1) /* bmap access */ 229#define FIBMAP _IO(0x00,1) /* bmap access */