insmod 失败并显示“模块中的未知符号”

insmod fails with “Unknown symbol in module”

我正在使用 Linuxmint Cinnamon 19 Ubuntu 18.04,内核版本 4.15.0-20-generic

编译时看到的如下:

make
make -C /lib/modules/`uname -r`/build SUBDIRS=/home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-20-generic'
  CC [M]  /home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.o
  Building modules, stage 2.
  MODPOST 1 modules
WARNING: "STUB_stop_elevator" [/home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.ko] undefined!
WARNING: "STUB_issue_request" [/home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.ko] undefined!
WARNING: "STUB_start_elevator" [/home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.ko] undefined!
  CC      /home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.mod.o
  LD [M]  /home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-20-generic'

然后我尝试使用 sudo insmod elevator.ko

安装模块
insmod: ERROR: could not insert module elevator.ko: Unknown symbol in module

在日志中看到: 消息 |尾

[    7.922763] 00:00:00.000285 main     Executable: /opt/VBoxGuestAdditions-5.2.4/sbin/VBoxService
               00:00:00.000286 main     Process ID: 832
               00:00:00.000286 main     Package type: LINUX_64BITS_GENERIC
[    7.923912] 00:00:00.001432 main     5.2.4 r119785 started. Verbose level = 0
[   11.048520] ISO 9660 Extensions: Microsoft Joliet Level 3
[   11.052008] ISO 9660 Extensions: RRIP_1991A
[   86.413368] elevator: loading out-of-tree module taints kernel.
[   86.413422] elevator: Unknown symbol STUB_stop_elevator (err 0)
[   86.413438] elevator: Unknown symbol STUB_issue_request (err 0)
[   86.413452] elevator: Unknown symbol STUB_start_elevator (err 0)

生成文件

obj-y := start_elevator.o issue_request.o stop_elevator.o
obj-m := elevator.o
KBUILD_CFLAGS += -fno-pie
PWD := $(shell pwd)
KDIR := /lib/modules/`uname -r`/build

default:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

clean:
    rm -f *.o *.ko *.mod.* Module.* modules.*

elevator.c

#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/linkage.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simulates elevator");

#define ENTRY_NAME "elevator"
#define ENTRY_SIZE 700
#define PERMS 0644
#define PARENT NULL
static struct file_operations fops;

static char * message;  
static int read_p;

enum States { OFFLINE, IDLE, LOADING, UP, DOWN };

#define MAX_PASSENGER_UNITS 10
#define MAX_WEIGHT_INT 15
#define MAX_WEIGHT_DEC 0


struct thread_parameter
{
    enum States Current_State;
    int Current_Floor;
    int Next_Floor;
    int Waiting_Passengers[10];
    int Total_Passengers[10];

    struct
    {
        int pass_units;
        int weight_int;
        int weight_dec;
    } Current_Load;

    struct list_head list;
    int id;
    struct task_struct * kthread;
    struct mutex mutex;
};

typedef struct
{
    int src;
    int dst;
    int pass_units;
    int weight_int;
    int weight_dec;
    struct list_head list;
} Passenger;

struct thread_parameter elevator;
struct list_head list;
struct list_head elev;
bool stop;


/*************************************************************************/

extern int (*STUB_start_elevator)(void);
int my_start_elevator(void)
{
    // start_elevator implementation

    int i;

    if (elevator.Current_State != OFFLINE)
        return 1;
    else
    {
//      try to initialize elevator:

        if (mutex_lock_interruptible(&elevator.mutex) == 0)
        {
            elevator.Current_Floor = 1;
            elevator.Next_Floor = 1;
            elevator.Current_Load.pass_units = 0;
            elevator.Current_Load.weight_int = 0;
            elevator.Current_Load.weight_dec = 0;
            elevator.Current_State = IDLE;

            for (i = 0; i < 10; i++)
            {
                elevator.Waiting_Passengers[i] = 0;
                elevator.Total_Passengers[i] = 0;
            }
        }
        mutex_unlock(&elevator.mutex);

        if (elevator.Current_State != IDLE)
            return -1;
    }

    return 0;
}


/*************************************************************************/

int load_elev(Passenger * p)
{
    struct list_head * temp;
    struct list_head * dummy;
    bool can_get_on = true;
    bool remove = false;

    if (mutex_lock_interruptible(&elevator.mutex) == 0)
    {
        list_for_each_safe(temp, dummy, &list)
        {
            p = list_entry(temp, Passenger, list);

            if (p->src != elevator.Current_Floor)
                can_get_on = false;

            if ((elevator.Current_Load.pass_units + p->pass_units) >
                MAX_PASSENGER_UNITS)
                can_get_on = false;

            if ((elevator.Current_Load.weight_int + p->weight_int) >
                MAX_WEIGHT_INT)
                can_get_on = false;

            if ((elevator.Current_Load.weight_int + p->weight_int) ==
                MAX_WEIGHT_INT &&
                (elevator.Current_Load.weight_dec == 5 ||
                p->weight_dec == 5))
                can_get_on = false;

            if (p->dst == elevator.Current_Floor)
                remove = true;
        }
    }
    mutex_unlock(&elevator.mutex);

    if (mutex_lock_interruptible(&elevator.mutex) == 0)
    {
        if (can_get_on && !remove)
        {
            if (elevator.Current_Load.pass_units == 0)
                INIT_LIST_HEAD(&elev);

            elevator.Current_Load.pass_units += p->pass_units;

            elevator.Current_Load.weight_int += p->weight_int;

            if (elevator.Current_Load.weight_dec == 5 &&
                p->weight_dec == 5)
            {
                elevator.Current_Load.weight_int++;
                elevator.Current_Load.weight_dec = 0;
            }
            else
            {
                elevator.Current_Load.weight_dec += p->weight_dec;
            }

            elevator.Waiting_Passengers[elevator.Current_Floor - 1]--;

            list_move_tail(temp, &elev);
        }
        else if (remove)
        {
            elevator.Waiting_Passengers[elevator.Current_Floor - 1]--;
            list_del(temp);
            kfree(p);
        }
    }
    mutex_unlock(&elevator.mutex);

    return 0;
}

int unload_elev(Passenger * p)
{
    // declare some temporary pointers
    struct list_head * temp;
    struct list_head * dummy;

    // use this since you need to change the pointers
    if (mutex_lock_interruptible(&elevator.mutex) == 0)
    {
        list_for_each_safe(temp, dummy, &elev)
        {
            p = list_entry(temp, Passenger, list);

            if (p->dst == elevator.Current_Floor)
            {
                elevator.Current_Load.pass_units -= p->pass_units;

                elevator.Current_Load.weight_int -= p->weight_int;

                if (elevator.Current_Load.weight_dec == 0 &&
                    p->weight_dec == 5)
                {
                    elevator.Current_Load.weight_int--;
                    elevator.Current_Load.weight_dec = 5;
                }
                else
                {
                    elevator.Current_Load.weight_dec -=
                    p->weight_dec;
                }

                elevator.Total_Passengers[p->src - 1]++;

                list_del(temp); // init ver also reinits list
                kfree(p);       // remember to free allocated data
            }
        }
    }
    mutex_unlock(&elevator.mutex);

    return 0;
}


/*************************************************************************/

int find_next_floor_up(int current_floor)
{
    struct list_head * temp;
    Passenger * p;

    int next_floor = -1;
    int closest_floor = 11; //set this initially 

    if (elevator.Current_Load.pass_units > 0)
    {
        list_for_each(temp, &elev)
        {
            p = list_entry(temp, Passenger, list);

            // for each passenger, if their dest is greater
            // than current floor
            // (i.e. they're going up), and if their dest is less
            // than the current closest_floor
            if (p->dst > current_floor && p->dst < closest_floor)
            {
                //make this our next_floor
                next_floor = p->dst;
                //update closest_floor to this particular passenger's 
                closest_floor = p->dst;
            }
        }   

        list_for_each(temp, &list)
        {
            p = list_entry(temp, Passenger, list);

            if (p->src > current_floor && p->src <= closest_floor &&
                p->dst > current_floor)
            {
                next_floor = p->src;
                closest_floor = p->src;
            }       
        }
    }

    return next_floor;
}

int find_next_floor_down(int current_floor)
{
    struct list_head * temp;
    Passenger * p;

    int next_floor = -1;
    int closest_floor = 0;

    if (elevator.Current_Load.pass_units > 0)
    {   
        list_for_each(temp, &elev)
        {
            p = list_entry(temp, Passenger, list);

            if (p->dst < current_floor && p->dst > closest_floor)
            {
                next_floor = p->dst;
                closest_floor = p->dst;
            }
        }

        list_for_each(temp, &list)
        {
            p = list_entry(temp, Passenger, list);

            if (p->src < current_floor && p->src >= closest_floor &&
                p->dst < current_floor)
            {
                next_floor = p->src;
                closest_floor = p->src;
            }   
        }
    }

    return next_floor;
}


/*************************************************************************/


extern int (*STUB_issue_request)(int, int, int);
int my_issue_request(int p_type, int start_floor, int dest_floor)
{
    // issue_request implementation

    Passenger * p = NULL;
    struct list_head * temp;
    struct list_head * dummy;

    if (elevator.Current_State == IDLE)
        INIT_LIST_HEAD(&list);

    p = kmalloc(sizeof(Passenger), __GFP_RECLAIM);

    printk(KERN_NOTICE "MY_ISSUE_REQUEST FUNCTION ENTERED\n");

    if (p_type < 1 || p_type > 4 ||
        start_floor < 1 || start_floor > 10 ||
        dest_floor < 1 || dest_floor > 10)
    {
        return 1;
    }

    if (mutex_lock_interruptible(&elevator.mutex) == 0)
    {
        p->src = start_floor;
        p->dst = dest_floor;
        p->pass_units = 0;
        p->weight_int = 0;
        p->weight_dec = 0;

        switch (p_type)
        {
            case 1:
            {
                p->pass_units = 1;
                p->weight_int = 1;
                p->weight_dec = 0;
                break;
            }

            case 2:
            {
                p->pass_units = 1;
                p->weight_int = 0;
                p->weight_dec = 5;
                break;
            }

            case 3:
            {
                p->pass_units = 2;
                p->weight_int = 2;
                p->weight_dec = 0;
                break;
            }

            case 4:
            {
                p->pass_units = 2;
                p->weight_int = 3;
                p->weight_dec = 0;
                break;
            }
        }
    }
    mutex_unlock(&elevator.mutex);

    if (!stop)
    {
        if (mutex_lock_interruptible(&elevator.mutex) == 0)
        {
            list_add_tail(&p->list, &list);
            elevator.Waiting_Passengers[p->src - 1]++;
        }
        mutex_unlock(&elevator.mutex);

        if (elevator.Current_State == IDLE)
        {
            if (mutex_lock_interruptible(&elevator.mutex) == 0)
            {
                if (p->src == elevator.Current_Floor)
                {
                    elevator.Current_State = LOADING;
                    elevator.Next_Floor = p->dst;
                }
            }
            mutex_unlock(&elevator.mutex);

            if (mutex_lock_interruptible(&elevator.mutex) == 0)
            {
                if (elevator.Current_Floor != p->src)
                    elevator.Next_Floor = p->src;

                if (elevator.Next_Floor > elevator.Current_Floor)
                    elevator.Current_State = UP;
                else if (elevator.Next_Floor < elevator.Current_Floor)
                    elevator.Current_State = DOWN;
            }
            mutex_unlock(&elevator.mutex);
        }
        else if (elevator.Current_State == UP)
        {
            if (elevator.Current_Load.pass_units == 0)
            {
                if (mutex_lock_interruptible(&elevator.mutex) == 0)
                {
                    list_for_each_safe(temp, dummy, &list)
                    {
                        p = list_entry(temp, Passenger, list);
                        elevator.Next_Floor = p->src;
                        break;
                    }       

                    list_for_each_safe(temp, dummy, &list)
                    {
                        p = list_entry(temp, Passenger, list);

                        if (p->src > elevator.Current_Floor &&
                            p->src <= elevator.Next_Floor &&
                            p->dst > elevator.Current_Floor)
                        {
                            elevator.Next_Floor = p->src;
                        }
                    }
                }       
                mutex_unlock(&elevator.mutex);
            }
        }
        else if (elevator.Current_State == DOWN)
        {
            if (mutex_lock_interruptible(&elevator.mutex) == 0)
            {
                list_for_each_safe(temp, dummy, &list)
                {
                    p = list_entry(temp, Passenger, list);

                    if (p->src < elevator.Current_Floor &&
                        p->src >= elevator.Next_Floor &&
                        p->dst < elevator.Current_Floor)
                    {
                        elevator.Next_Floor = p->src;
                    }
                }
            }
            mutex_unlock(&elevator.mutex);      
        }
    }

    return 0;
}


/*************************************************************************/

extern int (*STUB_stop_elevator)(void);
int my_stop_elevator(void)
{
    // stop_elevator implementation

/*
    deactivates elevator, elevator will
    process no more new requests, but will
    offload all current passengers
*/

    if (mutex_lock_interruptible(&elevator.mutex) == 0)
    {
        stop = true;
    }
    mutex_unlock(&elevator.mutex);

    while (elevator.Current_Load.pass_units != 0){}

    if (mutex_lock_interruptible(&elevator.mutex) == 0)
    {
        elevator.Current_State = OFFLINE;
        elevator.Current_Floor = 0;
        elevator.Next_Floor = 0;
    }
    mutex_unlock(&elevator.mutex);

    return 0;
}


/*************************************************************************/

int elevator_service(void * data)
{
    struct thread_parameter * parm = data;
    Passenger * p = NULL;
    struct list_head * temp;
    struct list_head * dummy;

    int i;
    bool waiting = false;

    printk(KERN_NOTICE "ELEVATOR_SERVICE FUNCTION ENTERED\n");

    while (!kthread_should_stop())
    {
        if (parm->Current_State != OFFLINE && parm->Current_State != IDLE)
        {
            if (parm->Current_State == LOADING)
            {
                ssleep(1);

                // if there are passengers on elevator, call unload_elev
                if (parm->Current_Load.pass_units > 0)
                    unload_elev(p);

                if (!stop)
                {
                    // if stop_elevator hasn't been called, call load_elev
                    load_elev(p);
                }
                else
                {
                    // if stop_elevator has been called, delete
                    // all waiting passengers from list
                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        list_for_each_safe(temp, dummy, &list)
                        {
                            p = list_entry(temp, Passenger, list);
                            list_del(temp);
                            kfree(p);
                        }
                    }
                    mutex_unlock(&elevator.mutex);
                }

                if (mutex_lock_interruptible(&parm->mutex) == 0)
                {
                    for (i = 0; i < 10; i++)
                    {
                        if (parm->Waiting_Passengers[i] > 0)
                            waiting = true;         
                    }
                }
                mutex_unlock(&elevator.mutex);

                // if there are no passengers on elevator
                // and no passengers waiting on any floor
                if (parm->Current_Load.pass_units == 0 && !waiting)
                {
                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {       
                        parm->Current_State = IDLE;
                    }
                    mutex_unlock(&elevator.mutex);
                }
                // if there are passengers on the elevator
                // and no passengers waiting on any floor
                else if (parm->Current_Load.pass_units > 0 && !waiting)
                {
                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        list_for_each_safe(temp, dummy, &elev)
                        {
                            p = list_entry(temp, Passenger, list);

                            parm->Next_Floor = p->dst;
                            break;
                        }   
                    }
                    mutex_unlock(&elevator.mutex);

                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        if (parm->Next_Floor > parm->Current_Floor)
                        {
                            if (find_next_floor_up(
                                parm->Current_Floor) > 0)
                            {
                                parm->Next_Floor =
                                find_next_floor_up(
                                parm->Current_Floor);
                            }

                            parm->Current_State = UP;
                        }
                        else
                        {
                            if (find_next_floor_down(
                                parm->Current_Floor) > 0)
                            {
                                parm->Next_Floor =
                                find_next_floor_down(
                                parm->Current_Floor);
                            }

                            parm->Current_State = DOWN;
                        }
                    }
                    mutex_unlock(&elevator.mutex);  
                }
                // if there are no passengers on the elevator
                // and at least one passenger is waiting on a floor
                else if (parm->Current_Load.pass_units == 0 && waiting)
                {
                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        list_for_each_safe(temp, dummy, &list)
                        {
                            p = list_entry(temp, Passenger, list);
                            parm->Next_Floor = p->src;

                            break;
                        }
                    }
                    mutex_unlock(&elevator.mutex);

                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        if (parm->Next_Floor > parm->Current_Floor)
                        {
                            if (find_next_floor_up(
                                parm->Current_Floor) > 0)
                            {
                                parm->Next_Floor =
                                find_next_floor_up(
                                parm->Current_Floor);
                            }

                            parm->Current_State = UP;
                        }
                        else
                        {
                            if (find_next_floor_down(
                                parm->Current_Floor) > 0)
                            {
                                parm->Next_Floor =
                                find_next_floor_down(
                                parm->Current_Floor);
                            }

                            parm->Current_State = DOWN;
                        }
                    }
                    mutex_unlock(&elevator.mutex);
                }
                // if there is at least one passenger on the elevator
                // and at least one passenger waiting on a floor
                else
                {
                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        list_for_each_safe(temp, dummy, &elev)
                        {
                            p = list_entry(temp, Passenger, list);
                            parm->Next_Floor = p->dst;

                            break;
                        }
                    }
                    mutex_unlock(&elevator.mutex);

                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        if (parm->Next_Floor > parm->Current_Floor)
                        {
                            if (find_next_floor_up(
                                parm->Current_Floor) > 0)
                            {
                                parm->Next_Floor =
                                find_next_floor_up(
                                parm->Current_Floor);
                            }

                            parm->Current_State = UP;
                        }
                        else
                        {
                            if (find_next_floor_down(
                                parm->Current_Floor) > 0)
                            {
                                parm->Next_Floor =
                                find_next_floor_down(
                                parm->Current_Floor);
                            }

                            parm->Current_State = DOWN;
                        }
                    }
                    mutex_unlock(&elevator.mutex);      
                }
            }
            else if (parm->Current_State == UP)
            {
                while (parm->Current_Floor != parm->Next_Floor)
                {
                    ssleep(2);

                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        parm->Current_Floor++;
                    }
                    mutex_unlock(&elevator.mutex);
                }

                if (mutex_lock_interruptible(&parm->mutex) == 0)
                {
                    parm->Current_State = LOADING;  
                }
                mutex_unlock(&elevator.mutex);
            }

            else // (parm->Current_State == DOWN)
            {
                while (parm->Current_Floor != parm->Next_Floor)
                {
                    ssleep(2);

                    if (mutex_lock_interruptible(&parm->mutex) == 0)
                    {
                        parm->Current_Floor--;
                    }
                    mutex_unlock(&elevator.mutex);
                }

                if (mutex_lock_interruptible(&parm->mutex) == 0)
                {
                    parm->Current_State = LOADING;  
                }
                mutex_unlock(&elevator.mutex);  
            }
        }
    }

    return 0;
}

void thread_init_parameter(struct thread_parameter * parm)
{
    parm->Current_State = OFFLINE;

    mutex_init(&parm->mutex);

    parm->kthread = kthread_run(elevator_service, parm,
                    "elevator in service"); 
}

/*************************************************************************/

int elevator_proc_open(struct inode *sp_inode, struct file *sp_file)
{
    char * buf = kmalloc (sizeof(char) * 100, __GFP_RECLAIM);   
    int i;

    if (buf == NULL)
    {
        printk(KERN_WARNING "print_time");
        return -ENOMEM;
    }

    printk(KERN_INFO "proc called open\n");
    printk(KERN_NOTICE "PROC_OPEN FUNCTION ENTERED\n");

    read_p = 1;
    message = kmalloc(sizeof(char) * ENTRY_SIZE,
             __GFP_RECLAIM | __GFP_IO | __GFP_FS);

    if (message == NULL)
    {
        printk(KERN_WARNING "time_proc_open");
        return -ENOMEM;
    }

    strcpy(message, "");
    switch (elevator.Current_State)
    {
        case 0:
        {
            sprintf(buf, "State: OFFLINE\n");
            break;
        }

        case 1:
        {
            sprintf(buf, "State: IDLE\n");
            break;
        }

        case 2:
        {
            sprintf(buf, "State: LOADING\n");
            break;
        }

        case 3:
        {
            sprintf(buf, "State: UP\n");
            break;
        }

        case 4:
        {
            sprintf(buf, "State: DOWN\n");
            break;
        }

        strcat(message, buf);   

        sprintf(buf, "Current floor: %d\n", elevator.Current_Floor);
        strcat(message, buf);
    }

    sprintf(buf, "Next floor: %d\n", elevator.Next_Floor);
    strcat(message, buf);

    if (elevator.Current_Load.weight_int == 0 &&
        elevator.Current_Load.weight_dec == 0)
    {
        sprintf(buf,
        "Current load: %d passenger units, 0 weight units\n\n",
        elevator.Current_Load.pass_units);
    }       
    else
    {
        sprintf(buf,
        "Current load: %d passenger units, %d.%d weight units\n\n",
        elevator.Current_Load.pass_units,
        elevator.Current_Load.weight_int,
        elevator.Current_Load.weight_dec);
    }

    strcat(message, buf);

    for (i = 0; i < 10; i++)
    {
        sprintf(buf,
        "Floor %d: %d passengers waiting, %d passengers serviced\n",
        i + 1,
        elevator.Waiting_Passengers[i], elevator.Total_Passengers[i]);
        strcat(message, buf);
    }

    return 0;
}

ssize_t elevator_proc_read(struct file *sp_file, char __user *buf,
                           size_t size, loff_t *offset)
{
    int len = strlen(message);

    read_p = !read_p;
    if (read_p)
        return 0;

    printk(KERN_INFO "proc called read\n");

    copy_to_user(buf, message, len);
    return len;
}

int elevator_proc_release(struct inode *sp_inode, struct file *sp_file)
{
    printk(KERN_NOTICE "proc called release\n");
    kfree(message);
    return 0;
}


/*************************************************************************/

static int elevator_init(void)
{
    // all initialization code

    stop = false;
    STUB_start_elevator = my_start_elevator;
    STUB_issue_request = my_issue_request;
    STUB_stop_elevator = my_stop_elevator;

    printk(KERN_NOTICE "/proc/%s create\n", ENTRY_NAME);

    fops.open = elevator_proc_open;
    fops.read = elevator_proc_read;
    fops.release = elevator_proc_release;

    if (!proc_create(ENTRY_NAME, PERMS, NULL, &fops))
    {
        printk(KERN_WARNING "proc create\n");
        remove_proc_entry(ENTRY_NAME, NULL);
        return -ENOMEM;
    }

    thread_init_parameter(&elevator);
    if (IS_ERR(elevator.kthread))
    {
        printk(KERN_WARNING "error spawning thread");
        remove_proc_entry(ENTRY_NAME, NULL);
        return PTR_ERR(elevator.kthread);
    }

    return 0;
}
module_init(elevator_init);

static void elevator_exit(void)
{
    // all clean up code



    kthread_stop(elevator.kthread);
    remove_proc_entry(ENTRY_NAME, NULL);
    mutex_destroy(&elevator.mutex);
    printk(KERN_NOTICE "Removing /proc/%s\n", ENTRY_NAME);
}
module_exit(elevator_exit);

issue_request.c

#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/module.h>

/* System call stub */
int (*STUB_issue_request)(int, int, int) = NULL;
EXPORT_SYMBOL(STUB_issue_request);

/* System call wrapper */
asmlinkage int sys_issue_request(int p_type, int start_floor,
                                 int dest_floor)
{
    if (STUB_issue_request != NULL)
        return STUB_issue_request(p_type, start_floor, dest_floor);
    else
        return -ENOSYS;
}

start_elevator.c

#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/module.h>

/* System call stub */
int (*STUB_start_elevator)(void) = NULL;
EXPORT_SYMBOL(STUB_start_elevator);

/* System call wrapper */
asmlinkage int sys_start_elevator(void)
{
    if (STUB_start_elevator != NULL)
        return STUB_start_elevator();
    else
        return -ENOSYS;
}

stop_elevator.c

#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/module.h>

/* System call stub */
int (*STUB_stop_elevator)(void) = NULL;
EXPORT_SYMBOL(STUB_stop_elevator);

/* System call wrapper */
asmlinkage int sys_stop_elevator(void)
{
    if (STUB_stop_elevator != NULL)
        return STUB_stop_elevator();
    else
        return -ENOSYS;
}

函数是静态的,同一目录下只有一个makefile。所以我的问题是:为什么无法加载 elevator.ko 以及如何修复?

这很简单。靠近顶部的是这些:

WARNING: "STUB_stop_elevator" [/home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.ko] undefined!
WARNING: "STUB_issue_request" [/home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.ko] undefined!
WARNING: "STUB_start_elevator" [/home/lukas/Desktop/COP4610-Operating-Systems-Project-2-master/elevator/elevator.ko] undefined!

由于未定义的符号,您的模块将无法加载。一旦在构建时解决了这些问题,模块加载应该会更好地工作。看起来您的 link 只使用了 1 个目标文件。虽然我无权确认,但请尝试调整您的 Makefile 以列出所有目标文件;可能是 obj-m 不完整,应该列出与 obj-y 相同的文件。

如果您在加载模块时 运行 进入其他未定义的符号,并且它们在您的模块外部,则可能存在依赖性问题。对于这种情况,将您的模块复制到 /lib/modules/...... 并尝试使用 modprobe

加载