1

I need to change the buffer size in the character device by parameter, so that, for example, when I write

insmod chardev.ko len=6

echo "Have a nice day!" > /dev/chardev.ko

cat /dev/chardev.ko

My output would be:

Have a

I've simply tried to replace the msg[BUF_SIZE] by msg[len], but I receive an error 'variably modified at file scope'.

I have no idea how to proceed. Any hints?

Here's the code:

    /*
 *  chardev.c: Creates a read-only char device that says how many times
 *  you've read from the dev file
 */
 
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>    /* for put_user */
 
/*
 *  Prototypes - this would normally go in a .h file
 */
int init_module(void);
void cleanup_module(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
 
static int len=100;
module_param(len, int, S_IRUGO);
MODULE_PARM_DESC(len, "The length of buffer");
 
#define SUCCESS 0
#define DEVICE_NAME "chardev"   /* Dev name as it appears in /proc/devices   */
#define BUF_LEN 100
 
 
/*
 * Global variables are declared as static, so are global within the file.
 */
 
 
 
static int Major;       /* Major number assigned to our device driver */
static int Device_Open = 0; /* Is device open?
                 * Used to prevent multiple access to device */
static char msg[BUF_LEN];   /* The msg the device will give when asked */
static char *msg_Ptr;
 
static struct file_operations fops = {
    .read = device_read,
    .write = device_write,
    .open = device_open,
    .release = device_release
};
 
/*
 * This function is called when the module is loaded
 */
int init_module(void)
{
    Major = register_chrdev(0, DEVICE_NAME, &fops);
 
    if (Major < 0) {
      printk(KERN_ALERT "Registering char device failed with %d\n", Major);
      return Major;
    }
 
    printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
    printk(KERN_INFO "the driver, create a dev file with\n");
    printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
    // minor numbers are used to differentiate multiple instances of a
    // device that use the same driver.
    printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
    printk(KERN_INFO "the device file.\n");
    printk(KERN_INFO "Remove the device file and module when done.\n");
 
    return SUCCESS;
}
 
/*
 * This function is called when the module is unloaded
 */
void cleanup_module(void)
{
    /*
     * Unregister the device
     */
#if 0
    int ret = unregister_chrdev(Major, DEVICE_NAME);
    if (ret < 0)
        printk(KERN_ALERT "Error in unregister_chrdev: %d\n", ret);
#endif
    unregister_chrdev(Major, DEVICE_NAME);
}
 
/*
 * Methods
 */
 
/*
 * Called when a process tries to open the device file, like
 * "cat /dev/mycharfile"
 */
static int device_open(struct inode *inode, struct file *file)
{
    static int counter = 0;
 
    if (Device_Open)
        return -EBUSY;
 
    Device_Open++;
    sprintf(msg, "I already told you %d times Hello world!\n", counter++);
    msg_Ptr = msg;
    try_module_get(THIS_MODULE);
 
    return SUCCESS;
}
 
/*
 * Called when a process closes the device file.
 */
static int device_release(struct inode *inode, struct file *file)
{
    Device_Open--;      /* We're now ready for our next caller */
 
    /*
     * Decrement the usage count, or else once you opened the file, you'll
     * never get get rid of the module.
     */
    module_put(THIS_MODULE);
 
    return 0;
}
 
/*
 * Called when a process, which already opened the dev file, attempts to
 * read from it.
 */
static ssize_t device_read(struct file *filp,   /* see include/linux/fs.h   */
               char *buffer,    /* buffer to fill with data */
               size_t length,   /* length of the buffer     */
               loff_t * offset)
{
    /*
     * Number of bytes actually written to the buffer
     */
    int bytes_read = 0;
 
    /*
     * If we're at the end of the message,
     * return 0 signifying end of file
     */
    if (*msg_Ptr == 0)
        return 0;
 
    /*
     * Actually put the data into the buffer
     */
    while (length && *msg_Ptr) {
 
        /*
         * The buffer is in the user data segment, not the kernel
         * segment so "*" assignment won't work.  We have to use
         * put_user which copies data from the kernel data segment to
         * the user data segment.
         */
        put_user(*(msg_Ptr++), buffer++);
 
        length--;
        bytes_read++;
    }
 
    /*
     * Most read functions return the number of bytes put into the buffer
     */
    return bytes_read;
}
 
/*
 * Called when a process writes to dev file: echo "hi" > /dev/hello
 */
static ssize_t
device_write(struct file *filp, const char *buffer, size_t length, loff_t * off)
{
    int i;
 
    #ifdef DEBUG
        printk(KERN_INFO "device_write(%p,%s,%d", file, buffer, length)
    #endif // DEBUG
    for(i=0; (i<length && i<BUF_LEN) || i<len; i++)
    {
        get_user(msg[i], buffer+i);
    }
 
    msg_Ptr=msg;
    return i;
 
    }

https://pastebin.com/wQP9p42G

Thanks in advance!

Community
  • 1
  • 1
Coolerini
  • 51
  • 1
  • 7
  • Memory allocations (mostly) fall into 2 categories: Static sizes known at compile time, and dynamic sizes that aren't known until run time. Trying to declare `msg[len]` as a global is trying to do both at once. The compiler can't know at compile time how much room to leave for `msg`, and you aren't calling a dynamic memory allocation routine (malloc, kmalloc or some such) that is able to allocate memory at run time. – David Wohlferd Dec 11 '17 at 02:39
  • Possible duplicate of [error : variably modified 'd' at file scope](https://stackoverflow.com/questions/21672639/error-variably-modified-d-at-file-scope) – Tsyvarev Dec 11 '17 at 07:54
  • 1
    `I have no idea how to proceed. Any hints?` - Allocate buffer manually, using `kmalloc` (this is kernel replacement for `malloc`). – Tsyvarev Dec 11 '17 at 07:56

0 Answers0