ltp_tbio.c revision 49a41ae3b50c87b01fbd6e4e9dbd80d1a2ee18e0
1/*
2 * Copyright (c) International Business Machines  Corp., 2001
3 * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 *
19 * This module will test block io layer.
20 *
21 * module: tbio
22 *
23 *  FILE        : tbio.c
24 *  USAGE       : kernel_space:./load_tbio.sh
25 *                user_space  :./test_bio
26 *
27 *  DESCRIPTION : The module will test block i/o layer for kernel 2.5
28 *  REQUIREMENTS:
29 *                1) glibc 2.1.91 or above.
30 *
31 *  HISTORY     :
32 *      11/19/2003 Kai Zhao (ltcd3@cn.ibm.com)
33 *
34 *  CODE COVERAGE: 74.9% - fs/bio.c (Total Coverage)
35 *
36 */
37
38#include <linux/module.h>
39#include <linux/init.h>
40#include <linux/version.h>
41#include <linux/kernel.h>
42#include <linux/fs.h>
43#include <linux/errno.h>
44#include <linux/types.h>
45#include <linux/vmalloc.h>
46#include <linux/genhd.h>
47#include <linux/blkdev.h>
48#include <linux/buffer_head.h>
49
50#include "tbio.h"
51
52MODULE_AUTHOR("Kai Zhao <ltcd3@cn.ibm.com>");
53MODULE_AUTHOR("Alexey Kodanev <alexey.kodanev@oracle.com>");
54MODULE_DESCRIPTION(TMOD_DRIVER_NAME);
55MODULE_LICENSE("GPL");
56
57#define prk_err(fmt, ...) \
58	pr_err(TBIO_DEVICE_NAME ": " fmt "\n", ##__VA_ARGS__)
59#define prk_info(fmt, ...) \
60	pr_info(TBIO_DEVICE_NAME ": " fmt "\n", ##__VA_ARGS__)
61
62static int nsectors = 4096;
63module_param(nsectors, int, 0444);
64MODULE_PARM_DESC(nsectors, "The number of sectors");
65
66static struct bio *tbiop, *tbiop_dup;
67
68static struct tbio_device {
69	unsigned long size;
70	spinlock_t lock;
71	u8 *data;
72	struct gendisk *gd;
73	struct block_device *bdev;
74	struct request_queue *q;
75} tbio_dev;
76
77static int send_request(struct request_queue *q, struct bio *bio,
78	struct block_device *bdev, struct tbio_interface *inter,
79	int writing)
80{
81	struct request *rq;
82	rq = blk_make_request(q, bio, GFP_KERNEL);
83	if (!rq) {
84		prk_err("failed to make request");
85		return -EFAULT;
86	}
87
88	if ((!inter->cmd_len) || (inter->cmd_len > rq->cmd_len)) {
89		prk_err("invalid inter->cmd_len");
90		return -EFAULT;
91	}
92
93	rq->cmd_len = inter->cmd_len;
94
95	if (copy_from_user(rq->cmd, inter->cmd, inter->cmd_len))
96		goto out_request;
97
98	if (*(rq->cmd + rq->cmd_len - 1)) {
99		prk_err("rq->cmd is not null-terminated");
100		return -EFAULT;
101	}
102
103	rq->__sector = bio->bi_sector;
104
105	if (blk_execute_rq(q, bdev->bd_disk, rq, 0))
106		goto out_request;
107
108	blk_put_request(rq);
109
110	return 0;
111
112out_request:
113
114	blk_put_request(rq);
115	return -EFAULT;
116}
117
118static int tbio_io(struct block_device *bdev, struct tbio_interface *uptr)
119{
120	int ret;
121	tbio_interface_t inter;
122	struct bio *bio = NULL;
123	int reading = 0, writing = 0;
124	void *buf = NULL;
125	struct request_queue *q = bdev_get_queue(bdev);
126
127	if (copy_from_user(&inter, uptr, sizeof(tbio_interface_t))) {
128		prk_err("copy_from_user");
129		return -EFAULT;
130	}
131
132	if (inter.data_len > (q->limits.max_sectors << 9)) {
133		prk_err("inter.in_len > q->max_sectors << 9");
134		return -EIO;
135	}
136
137	if (inter.data_len) {
138
139		switch (inter.direction) {
140		default:
141			return -EINVAL;
142		case TBIO_TO_DEV:
143			writing = 1;
144			break;
145		case TBIO_FROM_DEV:
146			reading = 1;
147			break;
148		}
149
150		bio = bio_map_user(q, bdev, (unsigned long)inter.data,
151			inter.data_len, reading, GFP_KERNEL);
152
153		if (!bio) {
154			prk_err("bio_map_user failed");
155			buf = kmalloc(inter.data_len, q->bounce_gfp | GFP_USER);
156			if (!buf) {
157				prk_err("buffer no memory");
158				return -1;
159			}
160			ret = copy_from_user(buf, inter.data, inter.data_len);
161			if (ret)
162				prk_err("copy_from_user() failed");
163
164			prk_info("buffer %s\n, copy_from_user returns '%d'",
165				(char *)buf, ret);
166		}
167
168	}
169
170	send_request(q, bio, bdev, &inter, writing);
171
172	if (bio)
173		bio_unmap_user(bio);
174	return 0;
175}
176
177static int test_bio_put(struct bio *biop)
178{
179	if (biop)
180		bio_put(biop);
181
182	return 0;
183}
184
185static int test_bio_clone(void)
186{
187	tbiop_dup = bio_clone(tbiop, GFP_NOIO);
188	if (tbiop_dup == NULL) {
189		prk_err("bio_clone failed");
190		return -1;
191	}
192
193	test_bio_put(tbiop_dup);
194
195	return 0;
196}
197
198static int test_bio_add_page(void)
199{
200	int ret = 0, i = 0, offset = 0;
201	unsigned long addr = 0;
202	struct page *ppage = NULL;
203
204	for (i = 0; i < 128; i++) {
205
206		addr = get_zeroed_page(GFP_KERNEL);
207
208		if (addr == 0) {
209			prk_err("get free page failed %ld", addr);
210			ret = -1;
211			break;
212		}
213
214		ppage = virt_to_page(addr);
215		if (ppage == NULL) {
216			prk_err("covert virture page to page struct failed");
217			ret = -1;
218			break;
219		}
220
221		ret = bio_add_page(tbiop, ppage, PAGE_SIZE, offset);
222		if (ret < 0) {
223			prk_err("bio_add_page failed");
224			break;
225		}
226		offset += ret;
227	}
228
229	return ret;
230}
231
232static int test_do_bio_alloc(int num)
233{
234	tbiop = bio_alloc(GFP_KERNEL, num);
235	if (tbiop == NULL) {
236		prk_err("bio_alloc failed");
237		return -1;
238	}
239	bio_put(tbiop);
240
241	return 0;
242}
243
244static int test_bio_alloc(void)
245{
246	if (test_do_bio_alloc(2) < 0) {
247		prk_err("can not alloc bio for %d", 2);
248		return -1;
249	}
250
251	if (test_do_bio_alloc(8) < 0) {
252		prk_err("can not alloc bio for %d", 8);
253		return -1;
254	}
255
256	if (test_do_bio_alloc(32) < 0) {
257		prk_err("can not alloc bio for %d", 32);
258		return -1;
259	}
260
261	if (test_do_bio_alloc(96) < 0) {
262		prk_err("can not alloc bio for %d", 96);
263		return -1;
264	}
265
266	if (test_do_bio_alloc(BIO_MAX_PAGES) < 0) {
267		prk_err("can not alloc bio for %d", BIO_MAX_PAGES);
268		return -1;
269	}
270
271	tbiop = bio_alloc(GFP_KERNEL, BIO_MAX_PAGES);
272	if (tbiop == NULL) {
273		prk_err("bio_alloc failed");
274		return -1;
275	}
276
277	tbiop->bi_bdev = tbio_dev.bdev;
278	tbiop->bi_sector = 0;
279
280	return 0;
281}
282
283static int test_bio_split(struct block_device *bdev,
284			  struct tbio_interface *uptr)
285{
286	int ret;
287	tbio_interface_t inter;
288	struct bio *bio = NULL;
289	struct bio_pair *bio_pairp = NULL;
290	int reading = 0, writing = 0;
291	void *buf = NULL;
292	struct request_queue *q = bdev_get_queue(bdev);
293	if (!q) {
294		prk_err("bdev_get_queue() failed");
295		return -EFAULT;
296	}
297
298	prk_info("test_bio_split");
299
300	if (copy_from_user(&inter, uptr, sizeof(tbio_interface_t))) {
301		prk_err("copy_from_user");
302		return -EFAULT;
303	}
304
305	if (inter.data_len > (q->limits.max_sectors << 9)) {
306		prk_err("inter.in_len > q->limits.max_sectors << 9");
307		return -EIO;
308	}
309
310	prk_info("inter.data_len is %d", inter.data_len);
311	if (inter.data_len) {
312
313		switch (inter.direction) {
314		default:
315			return -EINVAL;
316		case TBIO_TO_DEV:
317			writing = 1;
318			break;
319		case TBIO_FROM_DEV:
320			reading = 1;
321			break;
322		}
323
324		bio = bio_map_user(q, bdev, (unsigned long)inter.data,
325			inter.data_len, reading, GFP_KERNEL);
326
327		if (!bio) {
328			prk_err("bio_map_user failed");
329			buf = kmalloc(inter.data_len, q->bounce_gfp | GFP_USER);
330			if (!buf) {
331				prk_err("buffer no memory");
332				return -1;
333			}
334			ret = copy_from_user(buf, inter.data, inter.data_len);
335			if (ret)
336				prk_err("copy_from_user() failed");
337
338			prk_info("buffer %s", (char *)buf);
339		} else {
340			bio_pairp = bio_split(bio, 2);
341
342			if (bio_pairp == NULL) {
343				prk_err("bio_split failed");
344				bio_unmap_user(bio);
345				return -1;
346			}
347		}
348
349	}
350
351	send_request(q, &(bio_pairp->bio1), bdev, &inter, writing);
352	q = bdev_get_queue(bdev);
353	send_request(q, &(bio_pairp->bio2), bdev, &inter, writing);
354
355	if (bio_pairp)
356		bio_pair_release(bio_pairp);
357
358	if (bio)
359		bio_unmap_user(bio);
360
361	return 0;
362}
363
364static int test_bio_get_nr_vecs(void)
365{
366	int number = 0;
367
368	number = bio_get_nr_vecs(tbio_dev.bdev);
369
370	if (number < 0) {
371		prk_err("bio_get_nr_vec failed");
372		return -1;
373	}
374
375	prk_info("bio_get_nr_vecs: %d", number);
376	return 0;
377}
378
379static int tbio_ioctl(struct block_device *blk, fmode_t mode,
380	unsigned cmd, unsigned long arg)
381{
382	int err = 0;
383
384	switch (cmd) {
385	case LTP_TBIO_DO_IO:
386		prk_info("TEST-CASE: LTP_TBIO_DO_IO:");
387		err = tbio_io(tbio_dev.bdev, (struct tbio_interface *)arg);
388		break;
389	case LTP_TBIO_CLONE:
390		prk_info("TEST-CASE: LTP_TBIO_CLONE:");
391		err = test_bio_clone();
392		break;
393	case LTP_TBIO_ADD_PAGE:
394		prk_info("TEST-CASE: LTP_TBIO_ADD_PAGE:");
395		err = test_bio_add_page();
396		break;
397	case LTP_TBIO_ALLOC:
398		prk_info("TEST-CASE: LTP_TBIO_ALLOC:");
399		err = test_bio_alloc();
400		break;
401	case LTP_TBIO_GET_NR_VECS:
402		prk_info("TEST-CASE: LTP_TBIO_GET_NR_VECS:");
403		err = test_bio_get_nr_vecs();
404		break;
405	case LTP_TBIO_PUT:
406		prk_info("TEST-CASE: LTP_TBIO_PUT:");
407		err = test_bio_put(tbiop);
408		break;
409	case LTP_TBIO_SPLIT:
410		prk_info("TEST-CASE: LTP_TBIO_SPLIT:");
411		err = test_bio_split(tbio_dev.bdev,
412			(struct tbio_interface *)arg);
413	break;
414	}
415
416	prk_info("TEST-CASE DONE");
417	return err;
418}
419
420static int tbio_transfer(struct request *req, struct tbio_device *dev)
421{
422	unsigned int i = 0, offset = 0;
423	char *buf;
424	unsigned long flags;
425	size_t size;
426
427	struct bio_vec *bv;
428	struct req_iterator iter;
429
430	size = blk_rq_cur_bytes(req);
431	prk_info("bio req of size %zu:", size);
432	offset = blk_rq_pos(req) * 512;
433
434	rq_for_each_segment(bv, req, iter) {
435		size = bv->bv_len;
436		prk_info("%s bio(%u), segs(%u) sect(%u) pos(%lu) off(%u)",
437			(bio_data_dir(iter.bio) == READ) ? "READ" : "WRITE",
438			i, bio_segments(iter.bio), bio_sectors(iter.bio),
439			iter.bio->bi_sector, offset);
440
441		if (get_capacity(req->rq_disk) * 512 < offset) {
442			prk_info("Error, small capacity %zu, offset %u",
443				get_capacity(req->rq_disk) * 512,
444				offset);
445			continue;
446		}
447
448		buf = bvec_kmap_irq(bv, &flags);
449		if (bio_data_dir(iter.bio) == WRITE)
450			memcpy(dev->data + offset, buf, size);
451		else
452			memcpy(buf, dev->data + offset, size);
453		offset += size;
454		flush_kernel_dcache_page(bv->bv_page);
455		bvec_kunmap_irq(buf, &flags);
456		++i;
457	}
458
459	return 0;
460}
461
462static void tbio_request(struct request_queue *q)
463{
464	int ret = 0;
465	struct request *req;
466
467	while ((req = blk_fetch_request(q)) != NULL) {
468
469		ret = tbio_transfer(req, &tbio_dev);
470
471		spin_unlock_irq(q->queue_lock);
472		blk_end_request_all(req, ret);
473		spin_lock_irq(q->queue_lock);
474	}
475}
476
477static int tbio_open(struct block_device *blk, fmode_t mode)
478{
479	tbio_dev.bdev = blk;
480
481	return 0;
482}
483
484#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
485static int tbio_release(struct gendisk *gd, fmode_t mode)
486#else
487static void tbio_release(struct gendisk *gd, fmode_t mode)
488#endif
489{
490
491#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
492	return 0;
493#endif
494}
495
496int tbio_media_changed(struct gendisk *gd)
497{
498	return 0;
499}
500
501int tbio_revalidate(struct gendisk *gd)
502{
503	return 0;
504}
505
506static const struct block_device_operations tbio_ops = {
507	.owner = THIS_MODULE,
508	.open = tbio_open,
509	.ioctl = tbio_ioctl,
510	.release = tbio_release,
511	.media_changed = tbio_media_changed,
512	.revalidate_disk = tbio_revalidate
513};
514
515static int __init tbio_init(void)
516{
517	tbio_dev.size = nsectors * 512;
518
519	tbio_dev.data = vmalloc(tbio_dev.size);
520	if (tbio_dev.data == NULL)
521		return -ENOMEM;
522	strcpy(tbio_dev.data, "tbio data");
523	tbio_dev.bdev = NULL;
524
525	TBIO_MAJOR = register_blkdev(0, DEVICE_NAME);
526	if (TBIO_MAJOR <= 0) {
527		prk_err("unable to get major number");
528		goto out;
529	}
530	prk_info("register_blkdev major %d", TBIO_MAJOR);
531
532	spin_lock_init(&tbio_dev.lock);
533	tbio_dev.q = blk_init_queue(tbio_request, &tbio_dev.lock);
534	if (!tbio_dev.q) {
535		prk_err("failed to init queue");
536		goto out_unregister;
537	}
538
539	tbio_dev.gd = alloc_disk(1);
540	if (!tbio_dev.gd)
541		goto out_unregister;
542	tbio_dev.gd->major	= TBIO_MAJOR;
543	tbio_dev.gd->first_minor	= 0;
544	tbio_dev.gd->fops		= &tbio_ops;
545	tbio_dev.gd->private_data	= &tbio_dev;
546	tbio_dev.gd->queue	= tbio_dev.q;
547	strcpy(tbio_dev.gd->disk_name, "tbio");
548	set_capacity(tbio_dev.gd, nsectors);
549	tbio_dev.gd->queue->queuedata = tbio_dev.gd;
550
551	add_disk(tbio_dev.gd);
552
553	return 0;
554
555out_unregister:
556	unregister_blkdev(TBIO_MAJOR, DEVICE_NAME);
557out:
558	vfree(tbio_dev.data);
559	return -ENOMEM;
560}
561module_init(tbio_init);
562
563static void tbio_exit(void)
564{
565	blk_cleanup_queue(tbio_dev.q);
566	del_gendisk(tbio_dev.gd);
567	put_disk(tbio_dev.gd);
568	unregister_blkdev(TBIO_MAJOR, DEVICE_NAME);
569	vfree(tbio_dev.data);
570	prk_info("exit");
571}
572module_exit(tbio_exit);
573