#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/ioctl.h> #include <linux/pm.h> #include <linux/genhd.h> #include <linux/bio.h> #include <linux/mm.h> #include <linux/swap.h> #include <linux/bio.h> #include <linux/blk.h> #include <linux/slab.h> #include <linux/mempool.h> #include <linux/workqueue.h> #include <linux/namei.h> #include <linux/mount.h> #include <linux/quotaops.h> #include <linux/pagemap.h> #include <linux/dnotify.h> #include <linux/smp_lock.h> #include <linux/personality.h> #include <linux/security.h> #include <linux/buffer_head.h> #include <asm/namei.h> #include <asm/uaccess.h> #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) #define IS_POSIX(fl) (fl->fl_flags & FL_POSIX) #define TEST_MEM_SIZE 4096 #define FALSE 0 #include "Ltpfs.h" static int ltpdev_open(struct inode *inode, struct file *pfile); static int ltpdev_release(struct inode *inode, struct file *pfile); static int ltpdev_ioctl(struct inode *pinode, struct file *pfile, unsigned int cmd, unsigned long arg); static int do_buffer_c_tests(void); static struct block_device_operations blkops = { open: ltpdev_open, release:ltpdev_release, ioctl: ltpdev_ioctl, }; int ltp_fs_major = LTPMAJOR; int test_iteration = 0; static char genhd_flags = 0; static struct gendisk *gd_ptr; static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; MODULE_AUTHOR("Martin Ridgeway <mridge@us.ibm.com>"); MODULE_DESCRIPTION(FS_LTP_TEST_DRIVER_NAME); MODULE_LICENSE("GPL"); /* * Device operations for the virtual FS devices */ static struct pm_dev *ltp_pm_dev = NULL; struct block_device *ltplookup_bdev(const char *path); int path_lookup(const char *name, unsigned int flags, struct nameidata *nd); //static int __emul_lookup_dentry(const char *name, struct nameidata *nd); void path_release(struct nameidata *nd); static int ltpdev_open(struct inode *pinode, struct file *pfile) { printk(KERN_ALERT "ltpdev_open \n"); return 0; } static int ltpdev_release(struct inode *pinode, struct file *pfile) { printk(KERN_ALERT "ltpdev_release \n"); return 0; } static int ltpdev_ioctl(struct inode *pinode, struct file *pfile, unsigned int cmd, unsigned long arg) { struct bio *my_bio = NULL; struct bio *my_bio_copy = NULL; request_queue_t *q = NULL; struct block_device *bdev = NULL; unsigned long uaddr; unsigned int bytes_done = 100; int error = 0; int rc = 0; /*****************************************************************************/ printk(KERN_ALERT "ltpdev_ioctl fs tests\n"); switch (cmd) { case LTPAIODEV_CMD: printk(KERN_ALERT "Running AIO FS tests \n"); printk(KERN_ALERT "AIO FS tests complete\n"); break; case LTPBIODEV_CMD: printk(KERN_ALERT "Running BIO FS tests \n"); my_bio = bio_alloc(GFP_KERNEL, 0); if (!my_bio) { printk(KERN_ALERT "Error getting kernel slab memory !!\n"); } else { printk(KERN_ALERT "kernel slab memory alloc OK\n"); } bio_endio(my_bio, bytes_done, error); printk(KERN_ALERT "Return from bio_endio = %d \n", error); my_bio_copy = bio_clone(my_bio, GFP_ATOMIC); if (!my_bio_copy) { printk(KERN_ALERT "Error getting kernel bio clone !!\n"); } else { printk(KERN_ALERT "kernel bio clone OK\n"); } my_bio_copy = bio_clone(my_bio, GFP_NOIO); if (!my_bio_copy) { printk(KERN_ALERT "Error getting kernel bio clone !!\n"); } else { printk(KERN_ALERT "kernel bio clone OK\n"); } // q = bdev_get_queue(my_bio->bi_bdev); // rc = bio_phys_segments(q, my_bio); // rc = bio_hw_segments(q, my_bio); bdev = lookup_bdev(LTP_FS_DEVICE_NAME); printk(KERN_ALERT "return from bdev size %d\n", bdev->bd_block_size); printk(KERN_ALERT "Return from phys_segments = %d \n", rc); // Don't use this API, causes system to hang and corrupts FS // bio_put(my_bio); (char *)uaddr = kmalloc(TEST_MEM_SIZE, GFP_KERNEL); my_bio_copy = bio_map_user(bdev, uaddr, TEST_MEM_SIZE, FALSE); printk(KERN_ALERT "Return from bio_map_user %p\n", my_bio_copy); do_buffer_c_tests(); printk(KERN_ALERT "BIO FS tests complete\n"); break; } return 0; } static int ltp_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) { return 0; } int init_module(void) { int result; printk(KERN_ALERT "ltpdev_init_module \n"); ltp_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, ltp_pm_callback); result = register_blkdev(ltp_fs_major, LTP_FS_DEV_NAME); printk(KERN_ALERT "LTP FS: register_blkdev result=%d major %d\n", result, ltp_fs_major); if (result < 0) { printk(KERN_ALERT "LTP FS: can't get major %d\n", ltp_fs_major); return result; } gd_ptr = kmalloc(sizeof(struct gendisk *), GFP_KERNEL); if (!gd_ptr) { printk(KERN_ALERT "ERROR getting memory !!!\n"); return 0; } gd_ptr = alloc_disk(1); printk(KERN_ALERT "gd_ptr after alloc = %p \n", gd_ptr); gd_ptr->major = ltp_fs_major; gd_ptr->first_minor = 0; gd_ptr->fops = &blkops; gd_ptr->driverfs_dev = NULL; gd_ptr->capacity = MAX_NUM_DISKS; gd_ptr->flags = genhd_flags; sprintf(gd_ptr->disk_name, LTP_FS_DEV_NAME); add_disk(gd_ptr); return 0; } void cleanup_module(void) { printk(KERN_ALERT "Exiting module and cleaning up \n"); pm_unregister(ltp_pm_dev); put_disk(gd_ptr); del_gendisk(gd_ptr); unregister_blkdev(ltp_fs_major, LTP_FS_DEV_NAME); } static int do_buffer_c_tests() { int line_no = 0; printk(KERN_ALERT "Starting buffer.c coverage tests... \n"); __buffer_error("Test file", line_no); printk(KERN_ALERT "buffer.c coverage tests complete...\n"); return 0; } /** * lookup_bdev - lookup a struct block_device by name * * @path: special file representing the block device * * Get a reference to the blockdevice at @path in the current * namespace if possible and return it. Return ERR_PTR(error) * otherwise. */ struct block_device *lookup_bdev(const char *path) { struct block_device *bdev; struct inode *inode; struct nameidata nd; int error; if (!path || !*path) return ERR_PTR(-EINVAL); error = path_lookup(path, LOOKUP_FOLLOW, &nd); if (error) return ERR_PTR(error); inode = nd.dentry->d_inode; error = -ENOTBLK; if (!S_ISBLK(inode->i_mode)) goto fail; error = -EACCES; if (nd.mnt->mnt_flags & MNT_NODEV) goto fail; error = bd_acquire(inode); if (error) goto fail; bdev = inode->i_bdev; out: path_release(&nd); return bdev; fail: bdev = ERR_PTR(error); goto out; } int bd_acquire(struct inode *inode) { struct block_device *bdev; spin_lock(&bdev_lock); if (inode->i_bdev) { atomic_inc(&inode->i_bdev->bd_count); spin_unlock(&bdev_lock); return 0; } spin_unlock(&bdev_lock); bdev = bdget(kdev_t_to_nr(inode->i_rdev)); if (!bdev) return -ENOMEM; spin_lock(&bdev_lock); if (!inode->i_bdev) { inode->i_bdev = bdev; inode->i_mapping = bdev->bd_inode->i_mapping; list_add(&inode->i_devices, &bdev->bd_inodes); } else if (inode->i_bdev != bdev) BUG(); spin_unlock(&bdev_lock); return 0; }