@@ -1175,6 +1175,59 @@ static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
return ret;
}
+static int kernfs_iop_create(struct inode *dir, struct dentry *dentry,
+ umode_t mode, bool excl)
+{
+ struct kernfs_node *parent = dir->i_private;
+ struct kernfs_node *kn;
+ struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops;
+
+ if (!scops || !scops->create)
+ return -EPERM;
+
+ if (!kernfs_get_active(parent))
+ return -ENODEV;
+
+ // TODO: add some locking to ensure that scops->create
+ // is called only once, and possibly to handle the O_EXCL case
+ WARN_ONCE(excl, "excl unimplemented");
+
+ kn = scops->create(parent, dentry->d_name.name, mode);
+
+ if (!kn)
+ return -EPERM;
+
+ if (IS_ERR(kn))
+ return PTR_ERR(kn);
+
+ d_instantiate(dentry, kernfs_get_inode(dir->i_sb, kn));
+
+ return 0;
+}
+
+static int kernfs_iop_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct kernfs_node *parent = dir->i_private;
+ struct kernfs_node *kn = d_inode(dentry)->i_private;
+ struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops;
+ int ret;
+
+
+ if (!scops || !scops->unlink)
+ return -EPERM;
+
+ if (!kernfs_get_active(parent))
+ return -ENODEV;
+
+ ret = scops->unlink(kn);
+ if (ret)
+ return ret;
+
+ drop_nlink(d_inode(dentry));
+ dput(dentry);
+ return 0;
+};
+
const struct inode_operations kernfs_dir_iops = {
.lookup = kernfs_iop_lookup,
.permission = kernfs_iop_permission,
@@ -1185,6 +1238,8 @@ const struct inode_operations kernfs_dir_iops = {
.mkdir = kernfs_iop_mkdir,
.rmdir = kernfs_iop_rmdir,
.rename = kernfs_iop_rename,
+ .create = kernfs_iop_create,
+ .unlink = kernfs_iop_unlink,
};
static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos)
@@ -179,6 +179,9 @@ struct kernfs_syscall_ops {
const char *new_name);
int (*show_path)(struct seq_file *sf, struct kernfs_node *kn,
struct kernfs_root *root);
+ struct kernfs_node* (*create)(struct kernfs_node *parent,
+ const char *name, umode_t mode);
+ int (*unlink)(struct kernfs_node *kn);
};
struct kernfs_root {
I'm building a generic firmware variable filesystem on top of kernfs and I'd like to be able to create and unlink files. The hooks are fairly straightforward. create() returns a kernfs_node*, which is safe with regards to cleanup on error paths, because there is no way that things can fail after that point in the current implementation. However, currently O_EXCL is not implemented and that may create failure paths, in which case we may need to revisit this later. Signed-off-by: Daniel Axtens <dja@axtens.net> --- fs/kernfs/dir.c | 55 ++++++++++++++++++++++++++++++++++++++++++ include/linux/kernfs.h | 3 +++ 2 files changed, 58 insertions(+)