summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/kernfs/dir.c33
-rw-r--r--include/linux/kernfs.h3
2 files changed, 32 insertions, 4 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 8c63ae1bccb6..bfbfb48f4ad8 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -654,22 +654,36 @@ static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry,
{
struct kernfs_node *parent = dir->i_private;
struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops;
+ int ret;
if (!kdops || !kdops->mkdir)
return -EPERM;
- return kdops->mkdir(parent, dentry->d_name.name, mode);
+ if (!kernfs_get_active(parent))
+ return -ENODEV;
+
+ ret = kdops->mkdir(parent, dentry->d_name.name, mode);
+
+ kernfs_put_active(parent);
+ return ret;
}
static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry)
{
struct kernfs_node *kn = dentry->d_fsdata;
struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops;
+ int ret;
if (!kdops || !kdops->rmdir)
return -EPERM;
- return kdops->rmdir(kn);
+ if (!kernfs_get_active(kn))
+ return -ENODEV;
+
+ ret = kdops->rmdir(kn);
+
+ kernfs_put_active(kn);
+ return ret;
}
static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -678,11 +692,24 @@ static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
struct kernfs_node *kn = old_dentry->d_fsdata;
struct kernfs_node *new_parent = new_dir->i_private;
struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops;
+ int ret;
if (!kdops || !kdops->rename)
return -EPERM;
- return kdops->rename(kn, new_parent, new_dentry->d_name.name);
+ if (!kernfs_get_active(kn))
+ return -ENODEV;
+
+ if (!kernfs_get_active(new_parent)) {
+ kernfs_put_active(kn);
+ return -ENODEV;
+ }
+
+ ret = kdops->rename(kn, new_parent, new_dentry->d_name.name);
+
+ kernfs_put_active(new_parent);
+ kernfs_put_active(kn);
+ return ret;
}
const struct inode_operations kernfs_dir_iops = {
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 02ac33435808..58a131ddc6a3 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -111,7 +111,8 @@ struct kernfs_node {
* kernfs_dir_ops may be specified on kernfs_create_root() to support
* directory manipulation syscalls. These optional callbacks are invoked
* on the matching syscalls and can perform any kernfs operations which
- * don't necessarily have to be the exact operation requested.
+ * don't necessarily have to be the exact operation requested. An active
+ * reference is held for each kernfs_node parameter.
*/
struct kernfs_dir_ops {
int (*mkdir)(struct kernfs_node *parent, const char *name,