aboutsummaryrefslogtreecommitdiffstats
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 11:59:15 -0500
commit80b9bbefc345079bddc4959de016ba4074b0c8d6 (patch)
tree24d24636b01d9f9e31b39e08a8cfd0978ce9fd9d
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>
-rw-r--r--fs/kernfs/dir.c44
-rw-r--r--fs/sysfs/mount.c2
-rw-r--r--include/linux/kernfs.h21
3 files changed, 63 insertions, 4 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);
583 583
584/** 584/**
585 * kernfs_create_root - create a new kernfs hierarchy 585 * kernfs_create_root - create a new kernfs hierarchy
586 * @kdops: optional directory syscall operations for the hierarchy
586 * @priv: opaque data associated with the new directory 587 * @priv: opaque data associated with the new directory
587 * 588 *
588 * Returns the root of the new hierarchy on success, ERR_PTR() value on 589 * Returns the root of the new hierarchy on success, ERR_PTR() value on
589 * failure. 590 * failure.
590 */ 591 */
591struct kernfs_root *kernfs_create_root(void *priv) 592struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
592{ 593{
593 struct kernfs_root *root; 594 struct kernfs_root *root;
594 struct kernfs_node *kn; 595 struct kernfs_node *kn;
@@ -610,6 +611,7 @@ struct kernfs_root *kernfs_create_root(void *priv)
610 kn->priv = priv; 611 kn->priv = priv;
611 kn->dir.root = root; 612 kn->dir.root = root;
612 613
614 root->dir_ops = kdops;
613 root->kn = kn; 615 root->kn = kn;
614 616
615 return root; 617 return root;
@@ -706,6 +708,42 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
706 return ret; 708 return ret;
707} 709}
708 710
711static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry,
712 umode_t mode)
713{
714 struct kernfs_node *parent = dir->i_private;
715 struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops;
716
717 if (!kdops || !kdops->mkdir)
718 return -EPERM;
719
720 return kdops->mkdir(parent, dentry->d_name.name, mode);
721}
722
723static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry)
724{
725 struct kernfs_node *kn = dentry->d_fsdata;
726 struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops;
727
728 if (!kdops || !kdops->rmdir)
729 return -EPERM;
730
731 return kdops->rmdir(kn);
732}
733
734static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
735 struct inode *new_dir, struct dentry *new_dentry)
736{
737 struct kernfs_node *kn = old_dentry->d_fsdata;
738 struct kernfs_node *new_parent = new_dir->i_private;
739 struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops;
740
741 if (!kdops || !kdops->rename)
742 return -EPERM;
743
744 return kdops->rename(kn, new_parent, new_dentry->d_name.name);
745}
746
709const struct inode_operations kernfs_dir_iops = { 747const struct inode_operations kernfs_dir_iops = {
710 .lookup = kernfs_iop_lookup, 748 .lookup = kernfs_iop_lookup,
711 .permission = kernfs_iop_permission, 749 .permission = kernfs_iop_permission,
@@ -715,6 +753,10 @@ const struct inode_operations kernfs_dir_iops = {
715 .removexattr = kernfs_iop_removexattr, 753 .removexattr = kernfs_iop_removexattr,
716 .getxattr = kernfs_iop_getxattr, 754 .getxattr = kernfs_iop_getxattr,
717 .listxattr = kernfs_iop_listxattr, 755 .listxattr = kernfs_iop_listxattr,
756
757 .mkdir = kernfs_iop_mkdir,
758 .rmdir = kernfs_iop_rmdir,
759 .rename = kernfs_iop_rename,
718}; 760};
719 761
720static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos) 762static 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)
62{ 62{
63 int err; 63 int err;
64 64
65 sysfs_root = kernfs_create_root(NULL); 65 sysfs_root = kernfs_create_root(NULL, NULL);
66 if (IS_ERR(sysfs_root)) 66 if (IS_ERR(sysfs_root))
67 return PTR_ERR(sysfs_root); 67 return PTR_ERR(sysfs_root);
68 68
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 321ed84ad4ce..d2c439db4efa 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -111,12 +111,27 @@ struct kernfs_node {
111 struct kernfs_iattrs *iattr; 111 struct kernfs_iattrs *iattr;
112}; 112};
113 113
114/*
115 * kernfs_dir_ops may be specified on kernfs_create_root() to support
116 * directory manipulation syscalls. These optional callbacks are invoked
117 * on the matching syscalls and can perform any kernfs operations which
118 * don't necessarily have to be the exact operation requested.
119 */
120struct kernfs_dir_ops {
121 int (*mkdir)(struct kernfs_node *parent, const char *name,
122 umode_t mode);
123 int (*rmdir)(struct kernfs_node *kn);
124 int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent,
125 const char *new_name);
126};
127
114struct kernfs_root { 128struct kernfs_root {
115 /* published fields */ 129 /* published fields */
116 struct kernfs_node *kn; 130 struct kernfs_node *kn;
117 131
118 /* private fields, do not use outside kernfs proper */ 132 /* private fields, do not use outside kernfs proper */
119 struct ida ino_ida; 133 struct ida ino_ida;
134 struct kernfs_dir_ops *dir_ops;
120}; 135};
121 136
122struct kernfs_open_file { 137struct kernfs_open_file {
@@ -206,7 +221,8 @@ struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
206void kernfs_get(struct kernfs_node *kn); 221void kernfs_get(struct kernfs_node *kn);
207void kernfs_put(struct kernfs_node *kn); 222void kernfs_put(struct kernfs_node *kn);
208 223
209struct kernfs_root *kernfs_create_root(void *priv); 224struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops,
225 void *priv);
210void kernfs_destroy_root(struct kernfs_root *root); 226void kernfs_destroy_root(struct kernfs_root *root);
211 227
212struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, 228struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
@@ -255,7 +271,8 @@ kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name,
255static inline void kernfs_get(struct kernfs_node *kn) { } 271static inline void kernfs_get(struct kernfs_node *kn) { }
256static inline void kernfs_put(struct kernfs_node *kn) { } 272static inline void kernfs_put(struct kernfs_node *kn) { }
257 273
258static inline struct kernfs_root *kernfs_create_root(void *priv) 274static inline struct kernfs_root *
275kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
259{ return ERR_PTR(-ENOSYS); } 276{ return ERR_PTR(-ENOSYS); }
260 277
261static inline void kernfs_destroy_root(struct kernfs_root *root) { } 278static inline void kernfs_destroy_root(struct kernfs_root *root) { }