[kernel] 在release方法里,而不是flush方法里释放

做一个文件系统(姑且叫它“蝗虫文件系统“),需要在进程退出时自动删除它打开的文件。另外此文件还支持poll(我自己做的,一般的文件系统不支持),支持poll当然需要等待队列,所以我把一个等待队列放在文件对应的struct inode里,实现该文件struct file_operations里的flush方法,在flush时删除文件并释放该等待队列(kfree)。
这样做似乎一切顺利,直到应用程序开始使用epoll:先在蝗虫文件系统里创建几个文件,再把它们的fd放入epoll(epoll_ctl),然后进程退出,如此多来几次,内核就panic了。还好我用的是QEMU,可以清楚看见在什么地方panic的,结果是 __fput --> eventpoll_release --> eventpoll_release_file --> ep_remove --> ep_unregister_pollwait --> remove_wait_queue,看看ep_unregister_pollwait的代码:

[fs/eventpoll.c --> ep_unregister_pollwait]
  1109 static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
  1110 {
  1111     int nwait;
  1112     struct list_head *lsthead = &epi->pwqlist;
  1113     struct eppoll_entry *pwq;
  1114
  1115     /* This is called without locks, so we need the atomic exchange */
  1116     nwait = xchg(&epi->nwait, 0);
  1117
  1118     if (nwait) {
  1119         while (!list_empty(lsthead)) {
  1120             pwq = list_entry(lsthead->next, struct eppoll_entry, llink);
  1121
  1122             ep_list_del(&pwq->llink);
  1123             remove_wait_queue(pwq->whead, &pwq->wait);
  1124             kmem_cache_free(pwq_cache, pwq);
  1125         }
  1126     }
  1127 }

在把多个文件句柄加入epoll里的时候,这些文件句柄对应的inode上的等待队列要被epoll挂在一个数据结构上(struct eppoll_entry),当进程退出,这些等待队列当然要从数据结构上拿掉,但是,这些等待队列已经被我kfree了,所以panic。看来把kfree放在flush是不行了,那放哪儿?有哪个调用是比eventpoll_release发生的更晚的?有!

[fs/file_table.c --> __fput]
  153 void fastcall __fput(struct file *file)
  154 {
  155     struct dentry *dentry = file->f_dentry;
  156     struct vfsmount *mnt = file->f_vfsmnt;
  157     struct inode *inode = dentry->d_inode;
  158
  159     might_sleep();
  160
  161     fsnotify_close(file);
  162     /*
  163      * The function eventpoll_release() should be the first called
  164      * in the file cleanup chain.
  165      */
  166     eventpoll_release(file);
  167     locks_remove_flock(file);
  168
  169     if (file->f_op && file->f_op->release)
  170         file->f_op->release(inode, file);
  171     security_file_free(file);
  172     if (unlikely(inode->i_cdev != NULL))
  173         cdev_put(inode->i_cdev);
  174     fops_put(file->f_op);
  175     if (file->f_mode & FMODE_WRITE)
  176         put_write_access(inode);
  177     file_kill(file);
  178     file->f_dentry = NULL;
  179     file->f_vfsmnt = NULL;
  180     file_free(file);
  181     dput(dentry);
  182     mntput(mnt);
  183 }

struct file_operations里的release方法就是在epoll释放之后调用的,所以应该把kfree挪到release里去执行。
照此改之,没有panic了。

相关文章

分类

留言:

关于文章

This page contains a single entry by DongHao published on 06 1, 2010 5:11 PM.

[linux] tail和poll无关 was the previous entry in this blog.

[kernel] 使用sendfile is the next entry in this blog.

Find recent content on the main index or look in the 存档 to find all content.