#include #include #include #include #include #include #include #include "mod.h" #include "dev.h" #include "debug.h" MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Suren A. Chilingaryan "); MODULE_DESCRIPTION("Kernel Memory Manager - a module to manipulate kernel memory"); MODULE_VERSION("0.0.1"); int kmm_minors = KMM_MINORS; module_param(kmm_minors, int, S_IRUGO); static dev_t kmm_devno; /**< major number */ static kmm_dev_t **kmm_devs = NULL; /**< per-device context */ static spinlock_t kmm_devs_lock; /**< lock protecting creation/destruction of devices */ static struct class *kmm_class; /**< device class */ static void kmm_module_cleanup(void) { int i; if (kmm_devs) { for (i = 0; i < kmm_minors; i++) { if (kmm_devs[i]) { if (kmm_devs[i]->dev) device_destroy(kmm_class, kmm_devs[i]->devno); cdev_del(&kmm_devs[i]->cdev); kfree(kmm_devs[i]); } } kfree(kmm_devs); } if (kmm_class) class_destroy(kmm_class); unregister_chrdev_region(kmm_devno, kmm_minors); } static int kmm_module_setup_cdev(void) { int i; int err = 0; dev_t devno; kmm_dev_t *dev; dev = kmalloc(sizeof(kmm_dev_t), GFP_KERNEL); if (!dev) { mod_info("Couldn't allocate memory. Device is not created.\n"); return -ENOMEM; } cdev_init(&dev->cdev, kmm_get_fops()); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = kmm_get_fops(); spin_lock(&kmm_devs_lock); for (i = 0; i < kmm_minors; i++) { if (!kmm_devs[i]) break; } if (i == kmm_minors) { mod_info("No free minor numbers left"); err = -EBUSY; goto fail; } devno = MKDEV(MAJOR(kmm_devno), MINOR(kmm_devno) + i); dev->devno = devno; err = cdev_add(&dev->cdev, devno, 1); if (err) { mod_info("Error %d adding device kmm%d", err, i); goto fail; } dev->dev = device_create(kmm_class, NULL, devno, dev, KMM_NODE_FMT, MINOR(kmm_devno) + i); if (!dev->dev) { mod_info("Error creating /dev/%s%d\n", KMM_NODE, MINOR(kmm_devno) + i); goto fail; } dev_set_drvdata(dev->dev, dev); kmm_devs[i] = dev; spin_unlock(&kmm_devs_lock); mod_info("Device /dev/%s%d added\n", KMM_NODE, MINOR(kmm_devno) + i); return 0; fail: spin_unlock(&kmm_devs_lock); kfree(dev); return err; } static int __init kmm_module_init(void) { int err; spin_lock_init(&kmm_devs_lock); if ((err = alloc_chrdev_region(&kmm_devno, 0, kmm_minors, KMM_NODE))) { mod_info("Couldn't allocate chrdev region. Module not loaded.\n"); goto alloc_chrdev_fail; } kmm_class = class_create(THIS_MODULE, KMM_NODE); if (IS_ERR(kmm_class)) { mod_info("No sysfs support. Module not loaded.\n"); goto fail; } kmm_devs = kmalloc(kmm_minors * sizeof(kmm_dev_t*), GFP_KERNEL); if (!kmm_devs) { mod_info("Couldn't allocate memory. Module not loaded.\n"); err = -ENOMEM; } memset(kmm_devs, 0, kmm_minors * sizeof(kmm_dev_t*)); mod_info("Major %d allocated to node '%s'\n", MAJOR(kmm_devno), KMM_NODE); err = kmm_module_setup_cdev(); if (err) goto fail; return 0; fail: kmm_module_cleanup(); alloc_chrdev_fail: return err; } static void __exit kmm_module_exit(void) { kmm_module_cleanup(); } module_init(kmm_module_init); module_exit(kmm_module_exit);