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