summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2009-03-23 17:51:17 -0300
committerGreg Kroah-Hartman <gregkh@suse.de>2009-05-02 10:57:02 -0700
commit38a9de467cba9d691a22fe689b759fad0dec4d69 (patch)
treee8e857a509d6f39bc646f17b53d8c199a62dc9f9
parent7f871d00b7b32cafb8800a45b1d4eca94479deff (diff)
anon_inodes: use fops->owner for module refcount
There is an imbalance for anonymous inodes. If the fops->owner field is set, the module reference count of owner is decreases on release. ("filp_close" --> "__fput" ---> "fops_put") On the other hand, anon_inode_getfd does not increase the module reference count of owner. This causes two problems: - if owner is set, the module refcount goes negative - if owner is not set, the module can be unloaded while code is running This patch changes anon_inode_getfd to be symmetric regarding fops->owner handling. I have checked all existing users of anon_inode_getfd. Noone sets fops->owner, thats why nobody has seen the module refcount negative. The refcounting was tested with a patched and unpatched KVM module.(see patch 2/2) I also did an epoll_open/close test. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Reviewed-by: Davide Libenzi <davidel@xmailserver.org> Signed-off-by: Avi Kivity <avi@redhat.com> (cherry picked from commit e3a2a0d4e5ace731e60e2eff4fb7056ecb34adc1) Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--fs/anon_inodes.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 3662dd44896b..96bbafbddc35 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -79,9 +79,12 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
if (IS_ERR(anon_inode_inode))
return -ENODEV;
+ if (fops->owner && !try_module_get(fops->owner))
+ return -ENOENT;
+
error = get_unused_fd_flags(flags);
if (error < 0)
- return error;
+ goto err_module;
fd = error;
/*
@@ -128,6 +131,8 @@ err_dput:
dput(dentry);
err_put_unused_fd:
put_unused_fd(fd);
+err_module:
+ module_put(fops->owner);
return error;
}
EXPORT_SYMBOL_GPL(anon_inode_getfd);