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