summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-12-11 16:03:00 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-17 08:59:15 -0800
commit80b9bbefc345079bddc4959de016ba4074b0c8d6 (patch)
tree24d24636b01d9f9e31b39e08a8cfd0978ce9fd9d /fs
parent19bbb926203dbcf3a03915e934c36d7681bf6e13 (diff)
kernfs: add kernfs_dir_ops
Add support for mkdir(2), rmdir(2) and rename(2) syscalls. This is implemented through optional kernfs_dir_ops callback table which can be specified on kernfs_create_root(). An implemented callback is invoked when the matching syscall is invoked. As kernfs keep dcache syncs with internal representation and revalidates dentries on each access, the implementation of these methods is extremely simple. Each just discovers the relevant kernfs_node(s) and invokes the requested callback which is allowed to do any kernfs operations and the end result doesn't necessarily have to match the expected semantics of the syscall. This will be used to convert cgroup to use kernfs instead of its own filesystem implementation. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/kernfs/dir.c44
-rw-r--r--fs/sysfs/mount.c2
2 files changed, 44 insertions, 2 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 42c5b9f23b41..510b5062ef30 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -583,12 +583,13 @@ EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns);
/**
* kernfs_create_root - create a new kernfs hierarchy
+ * @kdops: optional directory syscall operations for the hierarchy
* @priv: opaque data associated with the new directory
*
* Returns the root of the new hierarchy on success, ERR_PTR() value on
* failure.
*/
-struct kernfs_root *kernfs_create_root(void *priv)
+struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
{
struct kernfs_root *root;
struct kernfs_node *kn;
@@ -610,6 +611,7 @@ struct kernfs_root *kernfs_create_root(void *priv)
kn->priv = priv;
kn->dir.root = root;
+ root->dir_ops = kdops;
root->kn = kn;
return root;
@@ -706,6 +708,42 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
return ret;
}
+static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry,
+ umode_t mode)
+{
+ struct kernfs_node *parent = dir->i_private;
+ struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops;
+
+ if (!kdops || !kdops->mkdir)
+ return -EPERM;
+
+ return kdops->mkdir(parent, dentry->d_name.name, mode);
+}
+
+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;
+
+ if (!kdops || !kdops->rmdir)
+ return -EPERM;
+
+ return kdops->rmdir(kn);
+}
+
+static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_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;
+
+ if (!kdops || !kdops->rename)
+ return -EPERM;
+
+ return kdops->rename(kn, new_parent, new_dentry->d_name.name);
+}
+
const struct inode_operations kernfs_dir_iops = {
.lookup = kernfs_iop_lookup,
.permission = kernfs_iop_permission,
@@ -715,6 +753,10 @@ const struct inode_operations kernfs_dir_iops = {
.removexattr = kernfs_iop_removexattr,
.getxattr = kernfs_iop_getxattr,
.listxattr = kernfs_iop_listxattr,
+
+ .mkdir = kernfs_iop_mkdir,
+ .rmdir = kernfs_iop_rmdir,
+ .rename = kernfs_iop_rename,
};
static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos)
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 701a56f341c6..6211230814fd 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -62,7 +62,7 @@ int __init sysfs_init(void)
{
int err;
- sysfs_root = kernfs_create_root(NULL);
+ sysfs_root = kernfs_create_root(NULL, NULL);
if (IS_ERR(sysfs_root))
return PTR_ERR(sysfs_root);