/** * kernfs_create_root - create a new kernfs hierarchy * @scops: optional syscall operations for the hierarchy * @flags: KERNFS_ROOT_* flags * @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(struct kernfs_syscall_ops *scops, unsigned int flags, void *priv) { struct kernfs_root *root; struct kernfs_node *kn; root = kzalloc(sizeof(*root), GFP_KERNEL); if (!root) return ERR_PTR(-ENOMEM); ida_init(&root->ino_ida); INIT_LIST_HEAD(&root->supers); kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, KERNFS_DIR); if (!kn) { ida_destroy(&root->ino_ida); kfree(root); return ERR_PTR(-ENOMEM); } kn->priv = priv; kn->dir.root = root; root->syscall_ops = scops; root->flags = flags; root->kn = kn; init_waitqueue_head(&root->deactivate_waitq); if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED)) kernfs_activate(kn); return root; }
/** * kernfs_add_one - add kernfs_node to parent without warning * @kn: kernfs_node to be added * * The caller must already have initialized @kn->parent. This * function increments nlink of the parent's inode if @kn is a * directory and link into the children list of the parent. * * RETURNS: * 0 on success, -EEXIST if entry with the given name already * exists. */ int kernfs_add_one(struct kernfs_node *kn) { struct kernfs_node *parent = kn->parent; struct kernfs_iattrs *ps_iattr; bool has_ns; int ret; mutex_lock(&kernfs_mutex); ret = -EINVAL; has_ns = kernfs_ns_enabled(parent); if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", has_ns ? "required" : "invalid", parent->name, kn->name)) goto out_unlock; if (kernfs_type(parent) != KERNFS_DIR) goto out_unlock; ret = -ENOENT; if (parent->flags & KERNFS_EMPTY_DIR) goto out_unlock; if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) goto out_unlock; kn->hash = kernfs_name_hash(kn->name, kn->ns); ret = kernfs_link_sibling(kn); if (ret) goto out_unlock; /* Update timestamps on the parent */ ps_iattr = parent->iattr; if (ps_iattr) { struct iattr *ps_iattrs = &ps_iattr->ia_iattr; ktime_get_real_ts(&ps_iattrs->ia_ctime); ps_iattrs->ia_mtime = ps_iattrs->ia_ctime; } mutex_unlock(&kernfs_mutex); /* * Activate the new node unless CREATE_DEACTIVATED is requested. * If not activated here, the kernfs user is responsible for * activating the node with kernfs_activate(). A node which hasn't * been activated is not visible to userland and its removal won't * trigger deactivation. */ if (!(kernfs_root(kn)->flags & KERNFS_ROOT_CREATE_DEACTIVATED)) kernfs_activate(kn); return 0; out_unlock: mutex_unlock(&kernfs_mutex); return ret; }
static int dslab_mkdir(struct kernfs_node *parent_kn, const char *name, umode_t mode) { struct kernfs_node *kn; int ret = 0; kn = kernfs_create_dir(parent_kn, name, mode, NULL); if (IS_ERR(kn)) { ret = PTR_ERR(kn); return ret; } kernfs_activate(kn); return ret; }
static struct dentry *dslab_mount(struct file_system_type *fs_type, int flags, const char *unused_dev_name, void *data) { struct dentry *dentry = NULL; struct kernfs_root *kf_root; struct kernfs_node *kn; bool new_sb; kf_root = kernfs_create_root(&dslab_kf_syscall_ops, KERNFS_ROOT_CREATE_DEACTIVATED, NULL); if (IS_ERR(kf_root)) goto out; kn = __kernfs_create_file(kf_root->kn, "dslab", FS_MODE, 0, &dslab_kernfs_ops, NULL, NULL, NULL); if (IS_ERR(kn)) goto destroy_root; dentry = kernfs_mount(fs_type, flags, kf_root, FS_MAGIC, &new_sb); if (IS_ERR(dentry) || !new_sb) goto destroy_kn; kernfs_activate(kf_root->kn); goto out; destroy_kn: kernfs_remove_by_name(kf_root->kn, "dslab"); destroy_root: kernfs_destroy_root(kf_root); kf_root = NULL; out: return dentry; }