views:

107

answers:

2

I'm doing a course on operating systems and we work in Linux Red Hat 8.0 AS part of an assignment I had to change sys close and sys open. Changes to sys close passed without an incident, but when I introduce the changes to sys close suddenly the OS encounters an error during booting, claiming it cannot mount root fs, and invokes panic. EIP is reportedly at sys close when this happens.

Here are the changes I made (look for the "HW1 additions" comment): In fs/open.c:

asmlinkage long sys_open(const char * filename, int flags, int mode)
{
    char * tmp;
    int fd, error;
    event_t* new_event;

#if BITS_PER_LONG != 32
    flags |= O_LARGEFILE;
#endif
    tmp = getname(filename);
    fd = PTR_ERR(tmp);
    if (!IS_ERR(tmp)) {
     fd = get_unused_fd();
     if (fd >= 0) {
      struct file *f = filp_open(tmp, flags, mode);
      error = PTR_ERR(f);
      if (IS_ERR(f))
       goto out_error;
      fd_install(fd, f);
     }
     /* HW1 additions */
     if (current->record_flag==1){
      new_event=(event_t*)kmalloc(sizeof(event_t), GFP_KERNEL);
      if (!new_event){
       new_event->type=Open;
       strcpy(new_event->filename, tmp);
       file_queue_add(*new_event, current->queue);
      }
     }
     /* End HW1 additions */
out:
     putname(tmp);
    }
    return fd;

out_error:
    put_unused_fd(fd);
    fd = error;
    goto out;
}

asmlinkage long sys_close(unsigned int fd)
{
    struct file * filp;
    struct files_struct *files = current->files;
    event_t* new_event;
    char* tmp = files->fd[fd]->f_dentry->d_name.name; 

    write_lock(&files->file_lock);
    if (fd >= files->max_fds)
     goto out_unlock;
    filp = files->fd[fd];
    if (!filp)
     goto out_unlock;
    files->fd[fd] = NULL;
    FD_CLR(fd, files->close_on_exec);
    __put_unused_fd(files, fd);
    write_unlock(&files->file_lock);
    /* HW1 additions */    
    if(current->record_flag == 1){
     new_event=(event_t*)kmalloc(sizeof(event_t), GFP_KERNEL);
     if (!new_event){
      new_event->type=Close;
      strcpy(new_event->filename, tmp);
      file_queue_add(*new_event, current->queue);
     }
    }
    /* End HW1 additions */
    return filp_close(filp, files);

out_unlock:
    write_unlock(&files->file_lock);
    return -EBADF;
}

The task_struct defined in schedule.h was changed at the end to include:

unsigned int record_flag; /* when zero: do not record. when one: record. */
file_queue* queue;

And file queue as well as event t are defined in a separate file as follows:

typedef enum {Open, Close} EventType;

typedef struct event_t{
    EventType type;
    char filename[256];
}event_t;

typedef struct file_quque_t{
    event_t queue[101];
    int head, tail; 
}file_queue;

file queue add works like this:

void file_queue_add(event_t event, file_queue* queue){ 
    queue->queue[queue->head]=event;
    queue->head = (queue->head+1) % 101;
    if (queue->head==queue->tail){
     queue->tail=(queue->tail+1) % 101;
    }
}
+2  A: 
if (!new_event) {
    new_event->type = …

That's equivalent to if (new_event == NULL). I think you mean if (new_event != NULL), which the kernel folks typically write as if (new_event).

ephemient
You are correct, but this doesn't fix the problem. What really confuses me is that since all processes are created to have record_flag set to 0, this code part shouldn't even have an effect, and yet the problem only happens after I introduce these changes.
Epsilon Vector
A: 

Can you please post the stackdump of the error. I don't see a place where queue_info structure is allocated memory. One more thing is you cannot be sure that process record_flag will be always zero if unassigned in kernel, because kernel is a long running program and memory contains garbage.

Its also possible to check the exact location in the function is occurring by looking at the stack trace.

Algorist