1f08c3bdfSopenharmony_ci
2f08c3bdfSopenharmony_ci#include <linux/kernel.h>
3f08c3bdfSopenharmony_ci#include <linux/module.h>
4f08c3bdfSopenharmony_ci#include <linux/init.h>
5f08c3bdfSopenharmony_ci#include <linux/types.h>
6f08c3bdfSopenharmony_ci#include <linux/fs.h>
7f08c3bdfSopenharmony_ci#include <linux/ioctl.h>
8f08c3bdfSopenharmony_ci#include <linux/pm.h>
9f08c3bdfSopenharmony_ci#include <linux/genhd.h>
10f08c3bdfSopenharmony_ci#include <linux/bio.h>
11f08c3bdfSopenharmony_ci#include <linux/mm.h>
12f08c3bdfSopenharmony_ci#include <linux/swap.h>
13f08c3bdfSopenharmony_ci#include <linux/bio.h>
14f08c3bdfSopenharmony_ci#include <linux/blk.h>
15f08c3bdfSopenharmony_ci#include <linux/slab.h>
16f08c3bdfSopenharmony_ci#include <linux/mempool.h>
17f08c3bdfSopenharmony_ci#include <linux/workqueue.h>
18f08c3bdfSopenharmony_ci#include <linux/namei.h>
19f08c3bdfSopenharmony_ci#include <linux/mount.h>
20f08c3bdfSopenharmony_ci#include <linux/quotaops.h>
21f08c3bdfSopenharmony_ci#include <linux/pagemap.h>
22f08c3bdfSopenharmony_ci#include <linux/dnotify.h>
23f08c3bdfSopenharmony_ci#include <linux/smp_lock.h>
24f08c3bdfSopenharmony_ci#include <linux/personality.h>
25f08c3bdfSopenharmony_ci#include <linux/security.h>
26f08c3bdfSopenharmony_ci#include <linux/buffer_head.h>
27f08c3bdfSopenharmony_ci#include <asm/namei.h>
28f08c3bdfSopenharmony_ci#include <asm/uaccess.h>
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_ci#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
31f08c3bdfSopenharmony_ci#define IS_POSIX(fl)	(fl->fl_flags & FL_POSIX)
32f08c3bdfSopenharmony_ci#define TEST_MEM_SIZE  4096
33f08c3bdfSopenharmony_ci#define FALSE          0
34f08c3bdfSopenharmony_ci#include "Ltpfs.h"
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_cistatic int ltpdev_open(struct inode *inode, struct file *pfile);
37f08c3bdfSopenharmony_cistatic int ltpdev_release(struct inode *inode, struct file *pfile);
38f08c3bdfSopenharmony_cistatic int ltpdev_ioctl(struct inode *pinode, struct file *pfile,
39f08c3bdfSopenharmony_ci			unsigned int cmd, unsigned long arg);
40f08c3bdfSopenharmony_cistatic int do_buffer_c_tests(void);
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_cistatic struct block_device_operations blkops = {
43f08c3bdfSopenharmony_ciopen:	ltpdev_open,
44f08c3bdfSopenharmony_cirelease:ltpdev_release,
45f08c3bdfSopenharmony_ciioctl:	ltpdev_ioctl,
46f08c3bdfSopenharmony_ci};
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_ciint ltp_fs_major = LTPMAJOR;
49f08c3bdfSopenharmony_ciint test_iteration = 0;
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_cistatic char genhd_flags = 0;
52f08c3bdfSopenharmony_cistatic struct gendisk *gd_ptr;
53f08c3bdfSopenharmony_cistatic spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ciMODULE_AUTHOR("Martin Ridgeway <mridge@us.ibm.com>");
56f08c3bdfSopenharmony_ciMODULE_DESCRIPTION(FS_LTP_TEST_DRIVER_NAME);
57f08c3bdfSopenharmony_ciMODULE_LICENSE("GPL");
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci/*
60f08c3bdfSopenharmony_ci * Device operations for the virtual FS devices
61f08c3bdfSopenharmony_ci */
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_cistatic struct pm_dev *ltp_pm_dev = NULL;
64f08c3bdfSopenharmony_cistruct block_device *ltplookup_bdev(const char *path);
65f08c3bdfSopenharmony_ciint path_lookup(const char *name, unsigned int flags, struct nameidata *nd);
66f08c3bdfSopenharmony_ci//static int __emul_lookup_dentry(const char *name, struct nameidata *nd);
67f08c3bdfSopenharmony_civoid path_release(struct nameidata *nd);
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_cistatic int ltpdev_open(struct inode *pinode, struct file *pfile)
70f08c3bdfSopenharmony_ci{
71f08c3bdfSopenharmony_ci	printk(KERN_ALERT "ltpdev_open \n");
72f08c3bdfSopenharmony_ci	return 0;
73f08c3bdfSopenharmony_ci}
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_cistatic int ltpdev_release(struct inode *pinode, struct file *pfile)
76f08c3bdfSopenharmony_ci{
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ci	printk(KERN_ALERT "ltpdev_release \n");
79f08c3bdfSopenharmony_ci	return 0;
80f08c3bdfSopenharmony_ci}
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_cistatic int ltpdev_ioctl(struct inode *pinode, struct file *pfile,
83f08c3bdfSopenharmony_ci			unsigned int cmd, unsigned long arg)
84f08c3bdfSopenharmony_ci{
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	struct bio *my_bio = NULL;
87f08c3bdfSopenharmony_ci	struct bio *my_bio_copy = NULL;
88f08c3bdfSopenharmony_ci	request_queue_t *q = NULL;
89f08c3bdfSopenharmony_ci	struct block_device *bdev = NULL;
90f08c3bdfSopenharmony_ci	unsigned long uaddr;
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci	unsigned int bytes_done = 100;
93f08c3bdfSopenharmony_ci
94f08c3bdfSopenharmony_ci	int error = 0;
95f08c3bdfSopenharmony_ci	int rc = 0;
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_ci    /*****************************************************************************/
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_ci	printk(KERN_ALERT "ltpdev_ioctl fs tests\n");
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	switch (cmd) {
102f08c3bdfSopenharmony_ci
103f08c3bdfSopenharmony_ci	case LTPAIODEV_CMD:
104f08c3bdfSopenharmony_ci		printk(KERN_ALERT "Running AIO FS tests \n");
105f08c3bdfSopenharmony_ci		printk(KERN_ALERT "AIO FS tests complete\n");
106f08c3bdfSopenharmony_ci		break;
107f08c3bdfSopenharmony_ci
108f08c3bdfSopenharmony_ci	case LTPBIODEV_CMD:
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci		printk(KERN_ALERT "Running BIO FS tests \n");
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci		my_bio = bio_alloc(GFP_KERNEL, 0);
113f08c3bdfSopenharmony_ci		if (!my_bio) {
114f08c3bdfSopenharmony_ci			printk(KERN_ALERT
115f08c3bdfSopenharmony_ci			       "Error getting kernel slab memory !!\n");
116f08c3bdfSopenharmony_ci		} else {
117f08c3bdfSopenharmony_ci			printk(KERN_ALERT "kernel slab memory alloc OK\n");
118f08c3bdfSopenharmony_ci		}
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_ci		bio_endio(my_bio, bytes_done, error);
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_ci		printk(KERN_ALERT "Return from bio_endio = %d \n", error);
123f08c3bdfSopenharmony_ci
124f08c3bdfSopenharmony_ci		my_bio_copy = bio_clone(my_bio, GFP_ATOMIC);
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_ci		if (!my_bio_copy) {
127f08c3bdfSopenharmony_ci			printk(KERN_ALERT
128f08c3bdfSopenharmony_ci			       "Error getting kernel bio clone !!\n");
129f08c3bdfSopenharmony_ci		} else {
130f08c3bdfSopenharmony_ci			printk(KERN_ALERT "kernel bio clone OK\n");
131f08c3bdfSopenharmony_ci		}
132f08c3bdfSopenharmony_ci
133f08c3bdfSopenharmony_ci		my_bio_copy = bio_clone(my_bio, GFP_NOIO);
134f08c3bdfSopenharmony_ci
135f08c3bdfSopenharmony_ci		if (!my_bio_copy) {
136f08c3bdfSopenharmony_ci			printk(KERN_ALERT
137f08c3bdfSopenharmony_ci			       "Error getting kernel bio clone !!\n");
138f08c3bdfSopenharmony_ci		} else {
139f08c3bdfSopenharmony_ci			printk(KERN_ALERT "kernel bio clone OK\n");
140f08c3bdfSopenharmony_ci		}
141f08c3bdfSopenharmony_ci
142f08c3bdfSopenharmony_ci//        q = bdev_get_queue(my_bio->bi_bdev);
143f08c3bdfSopenharmony_ci
144f08c3bdfSopenharmony_ci//        rc = bio_phys_segments(q, my_bio);
145f08c3bdfSopenharmony_ci
146f08c3bdfSopenharmony_ci//        rc = bio_hw_segments(q, my_bio);
147f08c3bdfSopenharmony_ci
148f08c3bdfSopenharmony_ci		bdev = lookup_bdev(LTP_FS_DEVICE_NAME);
149f08c3bdfSopenharmony_ci
150f08c3bdfSopenharmony_ci		printk(KERN_ALERT "return from bdev size %d\n",
151f08c3bdfSopenharmony_ci		       bdev->bd_block_size);
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_ci		printk(KERN_ALERT "Return from phys_segments = %d \n", rc);
154f08c3bdfSopenharmony_ci
155f08c3bdfSopenharmony_ci//        Don't use this API, causes system to hang and corrupts FS
156f08c3bdfSopenharmony_ci//        bio_put(my_bio);
157f08c3bdfSopenharmony_ci
158f08c3bdfSopenharmony_ci		(char *)uaddr = kmalloc(TEST_MEM_SIZE, GFP_KERNEL);
159f08c3bdfSopenharmony_ci
160f08c3bdfSopenharmony_ci		my_bio_copy = bio_map_user(bdev, uaddr, TEST_MEM_SIZE, FALSE);
161f08c3bdfSopenharmony_ci
162f08c3bdfSopenharmony_ci		printk(KERN_ALERT "Return from bio_map_user %p\n", my_bio_copy);
163f08c3bdfSopenharmony_ci
164f08c3bdfSopenharmony_ci		do_buffer_c_tests();
165f08c3bdfSopenharmony_ci
166f08c3bdfSopenharmony_ci		printk(KERN_ALERT "BIO FS tests complete\n");
167f08c3bdfSopenharmony_ci
168f08c3bdfSopenharmony_ci		break;
169f08c3bdfSopenharmony_ci	}
170f08c3bdfSopenharmony_ci
171f08c3bdfSopenharmony_ci	return 0;
172f08c3bdfSopenharmony_ci}
173f08c3bdfSopenharmony_ci
174f08c3bdfSopenharmony_cistatic int ltp_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
175f08c3bdfSopenharmony_ci{
176f08c3bdfSopenharmony_ci	return 0;
177f08c3bdfSopenharmony_ci}
178f08c3bdfSopenharmony_ci
179f08c3bdfSopenharmony_ciint init_module(void)
180f08c3bdfSopenharmony_ci{
181f08c3bdfSopenharmony_ci	int result;
182f08c3bdfSopenharmony_ci
183f08c3bdfSopenharmony_ci	printk(KERN_ALERT "ltpdev_init_module \n");
184f08c3bdfSopenharmony_ci
185f08c3bdfSopenharmony_ci	ltp_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, ltp_pm_callback);
186f08c3bdfSopenharmony_ci
187f08c3bdfSopenharmony_ci	result = register_blkdev(ltp_fs_major, LTP_FS_DEV_NAME);
188f08c3bdfSopenharmony_ci
189f08c3bdfSopenharmony_ci	printk(KERN_ALERT "LTP FS: register_blkdev result=%d major %d\n",
190f08c3bdfSopenharmony_ci	       result, ltp_fs_major);
191f08c3bdfSopenharmony_ci
192f08c3bdfSopenharmony_ci	if (result < 0) {
193f08c3bdfSopenharmony_ci		printk(KERN_ALERT "LTP FS: can't get major %d\n", ltp_fs_major);
194f08c3bdfSopenharmony_ci		return result;
195f08c3bdfSopenharmony_ci	}
196f08c3bdfSopenharmony_ci
197f08c3bdfSopenharmony_ci	gd_ptr = kmalloc(sizeof(struct gendisk *), GFP_KERNEL);
198f08c3bdfSopenharmony_ci
199f08c3bdfSopenharmony_ci	if (!gd_ptr) {
200f08c3bdfSopenharmony_ci		printk(KERN_ALERT "ERROR getting memory !!!\n");
201f08c3bdfSopenharmony_ci		return 0;
202f08c3bdfSopenharmony_ci	}
203f08c3bdfSopenharmony_ci
204f08c3bdfSopenharmony_ci	gd_ptr = alloc_disk(1);
205f08c3bdfSopenharmony_ci
206f08c3bdfSopenharmony_ci	printk(KERN_ALERT "gd_ptr after alloc = %p \n", gd_ptr);
207f08c3bdfSopenharmony_ci
208f08c3bdfSopenharmony_ci	gd_ptr->major = ltp_fs_major;
209f08c3bdfSopenharmony_ci	gd_ptr->first_minor = 0;
210f08c3bdfSopenharmony_ci	gd_ptr->fops = &blkops;
211f08c3bdfSopenharmony_ci	gd_ptr->driverfs_dev = NULL;
212f08c3bdfSopenharmony_ci	gd_ptr->capacity = MAX_NUM_DISKS;
213f08c3bdfSopenharmony_ci	gd_ptr->flags = genhd_flags;
214f08c3bdfSopenharmony_ci
215f08c3bdfSopenharmony_ci	sprintf(gd_ptr->disk_name, LTP_FS_DEV_NAME);
216f08c3bdfSopenharmony_ci
217f08c3bdfSopenharmony_ci	add_disk(gd_ptr);
218f08c3bdfSopenharmony_ci
219f08c3bdfSopenharmony_ci	return 0;
220f08c3bdfSopenharmony_ci}
221f08c3bdfSopenharmony_ci
222f08c3bdfSopenharmony_civoid cleanup_module(void)
223f08c3bdfSopenharmony_ci{
224f08c3bdfSopenharmony_ci
225f08c3bdfSopenharmony_ci	printk(KERN_ALERT "Exiting module and cleaning up \n");
226f08c3bdfSopenharmony_ci
227f08c3bdfSopenharmony_ci	pm_unregister(ltp_pm_dev);
228f08c3bdfSopenharmony_ci
229f08c3bdfSopenharmony_ci	put_disk(gd_ptr);
230f08c3bdfSopenharmony_ci
231f08c3bdfSopenharmony_ci	del_gendisk(gd_ptr);
232f08c3bdfSopenharmony_ci
233f08c3bdfSopenharmony_ci	unregister_blkdev(ltp_fs_major, LTP_FS_DEV_NAME);
234f08c3bdfSopenharmony_ci
235f08c3bdfSopenharmony_ci}
236f08c3bdfSopenharmony_ci
237f08c3bdfSopenharmony_cistatic int do_buffer_c_tests()
238f08c3bdfSopenharmony_ci{
239f08c3bdfSopenharmony_ci	int line_no = 0;
240f08c3bdfSopenharmony_ci
241f08c3bdfSopenharmony_ci	printk(KERN_ALERT "Starting buffer.c coverage tests... \n");
242f08c3bdfSopenharmony_ci
243f08c3bdfSopenharmony_ci	__buffer_error("Test file", line_no);
244f08c3bdfSopenharmony_ci
245f08c3bdfSopenharmony_ci	printk(KERN_ALERT "buffer.c coverage tests complete...\n");
246f08c3bdfSopenharmony_ci
247f08c3bdfSopenharmony_ci	return 0;
248f08c3bdfSopenharmony_ci}
249f08c3bdfSopenharmony_ci
250f08c3bdfSopenharmony_ci/**
251f08c3bdfSopenharmony_ci * lookup_bdev  - lookup a struct block_device by name
252f08c3bdfSopenharmony_ci *
253f08c3bdfSopenharmony_ci * @path:	special file representing the block device
254f08c3bdfSopenharmony_ci *
255f08c3bdfSopenharmony_ci * Get a reference to the blockdevice at @path in the current
256f08c3bdfSopenharmony_ci * namespace if possible and return it.  Return ERR_PTR(error)
257f08c3bdfSopenharmony_ci * otherwise.
258f08c3bdfSopenharmony_ci */
259f08c3bdfSopenharmony_cistruct block_device *lookup_bdev(const char *path)
260f08c3bdfSopenharmony_ci{
261f08c3bdfSopenharmony_ci	struct block_device *bdev;
262f08c3bdfSopenharmony_ci	struct inode *inode;
263f08c3bdfSopenharmony_ci	struct nameidata nd;
264f08c3bdfSopenharmony_ci	int error;
265f08c3bdfSopenharmony_ci
266f08c3bdfSopenharmony_ci	if (!path || !*path)
267f08c3bdfSopenharmony_ci		return ERR_PTR(-EINVAL);
268f08c3bdfSopenharmony_ci
269f08c3bdfSopenharmony_ci	error = path_lookup(path, LOOKUP_FOLLOW, &nd);
270f08c3bdfSopenharmony_ci	if (error)
271f08c3bdfSopenharmony_ci		return ERR_PTR(error);
272f08c3bdfSopenharmony_ci
273f08c3bdfSopenharmony_ci	inode = nd.dentry->d_inode;
274f08c3bdfSopenharmony_ci	error = -ENOTBLK;
275f08c3bdfSopenharmony_ci	if (!S_ISBLK(inode->i_mode))
276f08c3bdfSopenharmony_ci		goto fail;
277f08c3bdfSopenharmony_ci	error = -EACCES;
278f08c3bdfSopenharmony_ci	if (nd.mnt->mnt_flags & MNT_NODEV)
279f08c3bdfSopenharmony_ci		goto fail;
280f08c3bdfSopenharmony_ci	error = bd_acquire(inode);
281f08c3bdfSopenharmony_ci	if (error)
282f08c3bdfSopenharmony_ci		goto fail;
283f08c3bdfSopenharmony_ci	bdev = inode->i_bdev;
284f08c3bdfSopenharmony_ci
285f08c3bdfSopenharmony_ciout:
286f08c3bdfSopenharmony_ci	path_release(&nd);
287f08c3bdfSopenharmony_ci	return bdev;
288f08c3bdfSopenharmony_cifail:
289f08c3bdfSopenharmony_ci	bdev = ERR_PTR(error);
290f08c3bdfSopenharmony_ci	goto out;
291f08c3bdfSopenharmony_ci}
292f08c3bdfSopenharmony_ci
293f08c3bdfSopenharmony_ciint bd_acquire(struct inode *inode)
294f08c3bdfSopenharmony_ci{
295f08c3bdfSopenharmony_ci	struct block_device *bdev;
296f08c3bdfSopenharmony_ci	spin_lock(&bdev_lock);
297f08c3bdfSopenharmony_ci	if (inode->i_bdev) {
298f08c3bdfSopenharmony_ci		atomic_inc(&inode->i_bdev->bd_count);
299f08c3bdfSopenharmony_ci		spin_unlock(&bdev_lock);
300f08c3bdfSopenharmony_ci		return 0;
301f08c3bdfSopenharmony_ci	}
302f08c3bdfSopenharmony_ci	spin_unlock(&bdev_lock);
303f08c3bdfSopenharmony_ci	bdev = bdget(kdev_t_to_nr(inode->i_rdev));
304f08c3bdfSopenharmony_ci	if (!bdev)
305f08c3bdfSopenharmony_ci		return -ENOMEM;
306f08c3bdfSopenharmony_ci	spin_lock(&bdev_lock);
307f08c3bdfSopenharmony_ci	if (!inode->i_bdev) {
308f08c3bdfSopenharmony_ci		inode->i_bdev = bdev;
309f08c3bdfSopenharmony_ci		inode->i_mapping = bdev->bd_inode->i_mapping;
310f08c3bdfSopenharmony_ci		list_add(&inode->i_devices, &bdev->bd_inodes);
311f08c3bdfSopenharmony_ci	} else if (inode->i_bdev != bdev)
312f08c3bdfSopenharmony_ci		BUG();
313f08c3bdfSopenharmony_ci	spin_unlock(&bdev_lock);
314f08c3bdfSopenharmony_ci	return 0;
315f08c3bdfSopenharmony_ci}
316