162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/kernfs/dir.c - kernfs directory implementation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2001-3 Patrick Mochel 662306a36Sopenharmony_ci * Copyright (c) 2007 SUSE Linux Products GmbH 762306a36Sopenharmony_ci * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/sched.h> 1162306a36Sopenharmony_ci#include <linux/fs.h> 1262306a36Sopenharmony_ci#include <linux/namei.h> 1362306a36Sopenharmony_ci#include <linux/idr.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/security.h> 1662306a36Sopenharmony_ci#include <linux/hash.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "kernfs-internal.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */ 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * Don't use rename_lock to piggy back on pr_cont_buf. We don't want to 2362306a36Sopenharmony_ci * call pr_cont() while holding rename_lock. Because sometimes pr_cont() 2462306a36Sopenharmony_ci * will perform wakeups when releasing console_sem. Holding rename_lock 2562306a36Sopenharmony_ci * will introduce deadlock if the scheduler reads the kernfs_name in the 2662306a36Sopenharmony_ci * wakeup path. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(kernfs_pr_cont_lock); 2962306a36Sopenharmony_cistatic char kernfs_pr_cont_buf[PATH_MAX]; /* protected by pr_cont_lock */ 3062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic bool __kernfs_active(struct kernfs_node *kn) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci return atomic_read(&kn->active) >= 0; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic bool kernfs_active(struct kernfs_node *kn) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci lockdep_assert_held(&kernfs_root(kn)->kernfs_rwsem); 4262306a36Sopenharmony_ci return __kernfs_active(kn); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic bool kernfs_lockdep(struct kernfs_node *kn) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_LOCK_ALLOC 4862306a36Sopenharmony_ci return kn->flags & KERNFS_LOCKDEP; 4962306a36Sopenharmony_ci#else 5062306a36Sopenharmony_ci return false; 5162306a36Sopenharmony_ci#endif 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci if (!kn) 5762306a36Sopenharmony_ci return strlcpy(buf, "(null)", buflen); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return strlcpy(buf, kn->parent ? kn->name : "/", buflen); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* kernfs_node_depth - compute depth from @from to @to */ 6362306a36Sopenharmony_cistatic size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci size_t depth = 0; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci while (to->parent && to != from) { 6862306a36Sopenharmony_ci depth++; 6962306a36Sopenharmony_ci to = to->parent; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci return depth; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a, 7562306a36Sopenharmony_ci struct kernfs_node *b) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci size_t da, db; 7862306a36Sopenharmony_ci struct kernfs_root *ra = kernfs_root(a), *rb = kernfs_root(b); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (ra != rb) 8162306a36Sopenharmony_ci return NULL; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci da = kernfs_depth(ra->kn, a); 8462306a36Sopenharmony_ci db = kernfs_depth(rb->kn, b); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci while (da > db) { 8762306a36Sopenharmony_ci a = a->parent; 8862306a36Sopenharmony_ci da--; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci while (db > da) { 9162306a36Sopenharmony_ci b = b->parent; 9262306a36Sopenharmony_ci db--; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* worst case b and a will be the same at root */ 9662306a36Sopenharmony_ci while (b != a) { 9762306a36Sopenharmony_ci b = b->parent; 9862306a36Sopenharmony_ci a = a->parent; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return a; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/** 10562306a36Sopenharmony_ci * kernfs_path_from_node_locked - find a pseudo-absolute path to @kn_to, 10662306a36Sopenharmony_ci * where kn_from is treated as root of the path. 10762306a36Sopenharmony_ci * @kn_from: kernfs node which should be treated as root for the path 10862306a36Sopenharmony_ci * @kn_to: kernfs node to which path is needed 10962306a36Sopenharmony_ci * @buf: buffer to copy the path into 11062306a36Sopenharmony_ci * @buflen: size of @buf 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * We need to handle couple of scenarios here: 11362306a36Sopenharmony_ci * [1] when @kn_from is an ancestor of @kn_to at some level 11462306a36Sopenharmony_ci * kn_from: /n1/n2/n3 11562306a36Sopenharmony_ci * kn_to: /n1/n2/n3/n4/n5 11662306a36Sopenharmony_ci * result: /n4/n5 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * [2] when @kn_from is on a different hierarchy and we need to find common 11962306a36Sopenharmony_ci * ancestor between @kn_from and @kn_to. 12062306a36Sopenharmony_ci * kn_from: /n1/n2/n3/n4 12162306a36Sopenharmony_ci * kn_to: /n1/n2/n5 12262306a36Sopenharmony_ci * result: /../../n5 12362306a36Sopenharmony_ci * OR 12462306a36Sopenharmony_ci * kn_from: /n1/n2/n3/n4/n5 [depth=5] 12562306a36Sopenharmony_ci * kn_to: /n1/n2/n3 [depth=3] 12662306a36Sopenharmony_ci * result: /../.. 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * [3] when @kn_to is %NULL result will be "(null)" 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * Return: the length of the full path. If the full length is equal to or 13162306a36Sopenharmony_ci * greater than @buflen, @buf contains the truncated path with the trailing 13262306a36Sopenharmony_ci * '\0'. On error, -errno is returned. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_cistatic int kernfs_path_from_node_locked(struct kernfs_node *kn_to, 13562306a36Sopenharmony_ci struct kernfs_node *kn_from, 13662306a36Sopenharmony_ci char *buf, size_t buflen) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct kernfs_node *kn, *common; 13962306a36Sopenharmony_ci const char parent_str[] = "/.."; 14062306a36Sopenharmony_ci size_t depth_from, depth_to, len = 0; 14162306a36Sopenharmony_ci int i, j; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!kn_to) 14462306a36Sopenharmony_ci return strlcpy(buf, "(null)", buflen); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!kn_from) 14762306a36Sopenharmony_ci kn_from = kernfs_root(kn_to)->kn; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (kn_from == kn_to) 15062306a36Sopenharmony_ci return strlcpy(buf, "/", buflen); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci common = kernfs_common_ancestor(kn_from, kn_to); 15362306a36Sopenharmony_ci if (WARN_ON(!common)) 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci depth_to = kernfs_depth(common, kn_to); 15762306a36Sopenharmony_ci depth_from = kernfs_depth(common, kn_from); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci buf[0] = '\0'; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci for (i = 0; i < depth_from; i++) 16262306a36Sopenharmony_ci len += strlcpy(buf + len, parent_str, 16362306a36Sopenharmony_ci len < buflen ? buflen - len : 0); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Calculate how many bytes we need for the rest */ 16662306a36Sopenharmony_ci for (i = depth_to - 1; i >= 0; i--) { 16762306a36Sopenharmony_ci for (kn = kn_to, j = 0; j < i; j++) 16862306a36Sopenharmony_ci kn = kn->parent; 16962306a36Sopenharmony_ci len += strlcpy(buf + len, "/", 17062306a36Sopenharmony_ci len < buflen ? buflen - len : 0); 17162306a36Sopenharmony_ci len += strlcpy(buf + len, kn->name, 17262306a36Sopenharmony_ci len < buflen ? buflen - len : 0); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return len; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/** 17962306a36Sopenharmony_ci * kernfs_name - obtain the name of a given node 18062306a36Sopenharmony_ci * @kn: kernfs_node of interest 18162306a36Sopenharmony_ci * @buf: buffer to copy @kn's name into 18262306a36Sopenharmony_ci * @buflen: size of @buf 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * Copies the name of @kn into @buf of @buflen bytes. The behavior is 18562306a36Sopenharmony_ci * similar to strlcpy(). 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * Fills buffer with "(null)" if @kn is %NULL. 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * Return: the length of @kn's name and if @buf isn't long enough, 19062306a36Sopenharmony_ci * it's filled up to @buflen-1 and nul terminated. 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * This function can be called from any context. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ciint kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci unsigned long flags; 19762306a36Sopenharmony_ci int ret; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci read_lock_irqsave(&kernfs_rename_lock, flags); 20062306a36Sopenharmony_ci ret = kernfs_name_locked(kn, buf, buflen); 20162306a36Sopenharmony_ci read_unlock_irqrestore(&kernfs_rename_lock, flags); 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/** 20662306a36Sopenharmony_ci * kernfs_path_from_node - build path of node @to relative to @from. 20762306a36Sopenharmony_ci * @from: parent kernfs_node relative to which we need to build the path 20862306a36Sopenharmony_ci * @to: kernfs_node of interest 20962306a36Sopenharmony_ci * @buf: buffer to copy @to's path into 21062306a36Sopenharmony_ci * @buflen: size of @buf 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * Builds @to's path relative to @from in @buf. @from and @to must 21362306a36Sopenharmony_ci * be on the same kernfs-root. If @from is not parent of @to, then a relative 21462306a36Sopenharmony_ci * path (which includes '..'s) as needed to reach from @from to @to is 21562306a36Sopenharmony_ci * returned. 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * Return: the length of the full path. If the full length is equal to or 21862306a36Sopenharmony_ci * greater than @buflen, @buf contains the truncated path with the trailing 21962306a36Sopenharmony_ci * '\0'. On error, -errno is returned. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ciint kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, 22262306a36Sopenharmony_ci char *buf, size_t buflen) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci unsigned long flags; 22562306a36Sopenharmony_ci int ret; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci read_lock_irqsave(&kernfs_rename_lock, flags); 22862306a36Sopenharmony_ci ret = kernfs_path_from_node_locked(to, from, buf, buflen); 22962306a36Sopenharmony_ci read_unlock_irqrestore(&kernfs_rename_lock, flags); 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kernfs_path_from_node); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/** 23562306a36Sopenharmony_ci * pr_cont_kernfs_name - pr_cont name of a kernfs_node 23662306a36Sopenharmony_ci * @kn: kernfs_node of interest 23762306a36Sopenharmony_ci * 23862306a36Sopenharmony_ci * This function can be called from any context. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_civoid pr_cont_kernfs_name(struct kernfs_node *kn) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci unsigned long flags; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci spin_lock_irqsave(&kernfs_pr_cont_lock, flags); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci kernfs_name(kn, kernfs_pr_cont_buf, sizeof(kernfs_pr_cont_buf)); 24762306a36Sopenharmony_ci pr_cont("%s", kernfs_pr_cont_buf); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci spin_unlock_irqrestore(&kernfs_pr_cont_lock, flags); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/** 25362306a36Sopenharmony_ci * pr_cont_kernfs_path - pr_cont path of a kernfs_node 25462306a36Sopenharmony_ci * @kn: kernfs_node of interest 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * This function can be called from any context. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_civoid pr_cont_kernfs_path(struct kernfs_node *kn) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci unsigned long flags; 26162306a36Sopenharmony_ci int sz; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci spin_lock_irqsave(&kernfs_pr_cont_lock, flags); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci sz = kernfs_path_from_node(kn, NULL, kernfs_pr_cont_buf, 26662306a36Sopenharmony_ci sizeof(kernfs_pr_cont_buf)); 26762306a36Sopenharmony_ci if (sz < 0) { 26862306a36Sopenharmony_ci pr_cont("(error)"); 26962306a36Sopenharmony_ci goto out; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (sz >= sizeof(kernfs_pr_cont_buf)) { 27362306a36Sopenharmony_ci pr_cont("(name too long)"); 27462306a36Sopenharmony_ci goto out; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci pr_cont("%s", kernfs_pr_cont_buf); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciout: 28062306a36Sopenharmony_ci spin_unlock_irqrestore(&kernfs_pr_cont_lock, flags); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/** 28462306a36Sopenharmony_ci * kernfs_get_parent - determine the parent node and pin it 28562306a36Sopenharmony_ci * @kn: kernfs_node of interest 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * Determines @kn's parent, pins and returns it. This function can be 28862306a36Sopenharmony_ci * called from any context. 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * Return: parent node of @kn 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_cistruct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct kernfs_node *parent; 29562306a36Sopenharmony_ci unsigned long flags; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci read_lock_irqsave(&kernfs_rename_lock, flags); 29862306a36Sopenharmony_ci parent = kn->parent; 29962306a36Sopenharmony_ci kernfs_get(parent); 30062306a36Sopenharmony_ci read_unlock_irqrestore(&kernfs_rename_lock, flags); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return parent; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/** 30662306a36Sopenharmony_ci * kernfs_name_hash - calculate hash of @ns + @name 30762306a36Sopenharmony_ci * @name: Null terminated string to hash 30862306a36Sopenharmony_ci * @ns: Namespace tag to hash 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * Return: 31-bit hash of ns + name (so it fits in an off_t) 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_cistatic unsigned int kernfs_name_hash(const char *name, const void *ns) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci unsigned long hash = init_name_hash(ns); 31562306a36Sopenharmony_ci unsigned int len = strlen(name); 31662306a36Sopenharmony_ci while (len--) 31762306a36Sopenharmony_ci hash = partial_name_hash(*name++, hash); 31862306a36Sopenharmony_ci hash = end_name_hash(hash); 31962306a36Sopenharmony_ci hash &= 0x7fffffffU; 32062306a36Sopenharmony_ci /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ 32162306a36Sopenharmony_ci if (hash < 2) 32262306a36Sopenharmony_ci hash += 2; 32362306a36Sopenharmony_ci if (hash >= INT_MAX) 32462306a36Sopenharmony_ci hash = INT_MAX - 1; 32562306a36Sopenharmony_ci return hash; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int kernfs_name_compare(unsigned int hash, const char *name, 32962306a36Sopenharmony_ci const void *ns, const struct kernfs_node *kn) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci if (hash < kn->hash) 33262306a36Sopenharmony_ci return -1; 33362306a36Sopenharmony_ci if (hash > kn->hash) 33462306a36Sopenharmony_ci return 1; 33562306a36Sopenharmony_ci if (ns < kn->ns) 33662306a36Sopenharmony_ci return -1; 33762306a36Sopenharmony_ci if (ns > kn->ns) 33862306a36Sopenharmony_ci return 1; 33962306a36Sopenharmony_ci return strcmp(name, kn->name); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int kernfs_sd_compare(const struct kernfs_node *left, 34362306a36Sopenharmony_ci const struct kernfs_node *right) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci return kernfs_name_compare(left->hash, left->name, left->ns, right); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/** 34962306a36Sopenharmony_ci * kernfs_link_sibling - link kernfs_node into sibling rbtree 35062306a36Sopenharmony_ci * @kn: kernfs_node of interest 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * Link @kn into its sibling rbtree which starts from 35362306a36Sopenharmony_ci * @kn->parent->dir.children. 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * Locking: 35662306a36Sopenharmony_ci * kernfs_rwsem held exclusive 35762306a36Sopenharmony_ci * 35862306a36Sopenharmony_ci * Return: 35962306a36Sopenharmony_ci * %0 on success, -EEXIST on failure. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_cistatic int kernfs_link_sibling(struct kernfs_node *kn) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct rb_node **node = &kn->parent->dir.children.rb_node; 36462306a36Sopenharmony_ci struct rb_node *parent = NULL; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci while (*node) { 36762306a36Sopenharmony_ci struct kernfs_node *pos; 36862306a36Sopenharmony_ci int result; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci pos = rb_to_kn(*node); 37162306a36Sopenharmony_ci parent = *node; 37262306a36Sopenharmony_ci result = kernfs_sd_compare(kn, pos); 37362306a36Sopenharmony_ci if (result < 0) 37462306a36Sopenharmony_ci node = &pos->rb.rb_left; 37562306a36Sopenharmony_ci else if (result > 0) 37662306a36Sopenharmony_ci node = &pos->rb.rb_right; 37762306a36Sopenharmony_ci else 37862306a36Sopenharmony_ci return -EEXIST; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* add new node and rebalance the tree */ 38262306a36Sopenharmony_ci rb_link_node(&kn->rb, parent, node); 38362306a36Sopenharmony_ci rb_insert_color(&kn->rb, &kn->parent->dir.children); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* successfully added, account subdir number */ 38662306a36Sopenharmony_ci down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); 38762306a36Sopenharmony_ci if (kernfs_type(kn) == KERNFS_DIR) 38862306a36Sopenharmony_ci kn->parent->dir.subdirs++; 38962306a36Sopenharmony_ci kernfs_inc_rev(kn->parent); 39062306a36Sopenharmony_ci up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/** 39662306a36Sopenharmony_ci * kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree 39762306a36Sopenharmony_ci * @kn: kernfs_node of interest 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * Try to unlink @kn from its sibling rbtree which starts from 40062306a36Sopenharmony_ci * kn->parent->dir.children. 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * Return: %true if @kn was actually removed, 40362306a36Sopenharmony_ci * %false if @kn wasn't on the rbtree. 40462306a36Sopenharmony_ci * 40562306a36Sopenharmony_ci * Locking: 40662306a36Sopenharmony_ci * kernfs_rwsem held exclusive 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_cistatic bool kernfs_unlink_sibling(struct kernfs_node *kn) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci if (RB_EMPTY_NODE(&kn->rb)) 41162306a36Sopenharmony_ci return false; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); 41462306a36Sopenharmony_ci if (kernfs_type(kn) == KERNFS_DIR) 41562306a36Sopenharmony_ci kn->parent->dir.subdirs--; 41662306a36Sopenharmony_ci kernfs_inc_rev(kn->parent); 41762306a36Sopenharmony_ci up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci rb_erase(&kn->rb, &kn->parent->dir.children); 42062306a36Sopenharmony_ci RB_CLEAR_NODE(&kn->rb); 42162306a36Sopenharmony_ci return true; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci/** 42562306a36Sopenharmony_ci * kernfs_get_active - get an active reference to kernfs_node 42662306a36Sopenharmony_ci * @kn: kernfs_node to get an active reference to 42762306a36Sopenharmony_ci * 42862306a36Sopenharmony_ci * Get an active reference of @kn. This function is noop if @kn 42962306a36Sopenharmony_ci * is %NULL. 43062306a36Sopenharmony_ci * 43162306a36Sopenharmony_ci * Return: 43262306a36Sopenharmony_ci * Pointer to @kn on success, %NULL on failure. 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_cistruct kernfs_node *kernfs_get_active(struct kernfs_node *kn) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci if (unlikely(!kn)) 43762306a36Sopenharmony_ci return NULL; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (!atomic_inc_unless_negative(&kn->active)) 44062306a36Sopenharmony_ci return NULL; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (kernfs_lockdep(kn)) 44362306a36Sopenharmony_ci rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); 44462306a36Sopenharmony_ci return kn; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/** 44862306a36Sopenharmony_ci * kernfs_put_active - put an active reference to kernfs_node 44962306a36Sopenharmony_ci * @kn: kernfs_node to put an active reference to 45062306a36Sopenharmony_ci * 45162306a36Sopenharmony_ci * Put an active reference to @kn. This function is noop if @kn 45262306a36Sopenharmony_ci * is %NULL. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_civoid kernfs_put_active(struct kernfs_node *kn) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci int v; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (unlikely(!kn)) 45962306a36Sopenharmony_ci return; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (kernfs_lockdep(kn)) 46262306a36Sopenharmony_ci rwsem_release(&kn->dep_map, _RET_IP_); 46362306a36Sopenharmony_ci v = atomic_dec_return(&kn->active); 46462306a36Sopenharmony_ci if (likely(v != KN_DEACTIVATED_BIAS)) 46562306a36Sopenharmony_ci return; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci wake_up_all(&kernfs_root(kn)->deactivate_waitq); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/** 47162306a36Sopenharmony_ci * kernfs_drain - drain kernfs_node 47262306a36Sopenharmony_ci * @kn: kernfs_node to drain 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci * Drain existing usages and nuke all existing mmaps of @kn. Multiple 47562306a36Sopenharmony_ci * removers may invoke this function concurrently on @kn and all will 47662306a36Sopenharmony_ci * return after draining is complete. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistatic void kernfs_drain(struct kernfs_node *kn) 47962306a36Sopenharmony_ci __releases(&kernfs_root(kn)->kernfs_rwsem) 48062306a36Sopenharmony_ci __acquires(&kernfs_root(kn)->kernfs_rwsem) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(kn); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci lockdep_assert_held_write(&root->kernfs_rwsem); 48562306a36Sopenharmony_ci WARN_ON_ONCE(kernfs_active(kn)); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* 48862306a36Sopenharmony_ci * Skip draining if already fully drained. This avoids draining and its 48962306a36Sopenharmony_ci * lockdep annotations for nodes which have never been activated 49062306a36Sopenharmony_ci * allowing embedding kernfs_remove() in create error paths without 49162306a36Sopenharmony_ci * worrying about draining. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_ci if (atomic_read(&kn->active) == KN_DEACTIVATED_BIAS && 49462306a36Sopenharmony_ci !kernfs_should_drain_open_files(kn)) 49562306a36Sopenharmony_ci return; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (kernfs_lockdep(kn)) { 50062306a36Sopenharmony_ci rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); 50162306a36Sopenharmony_ci if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) 50262306a36Sopenharmony_ci lock_contended(&kn->dep_map, _RET_IP_); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci wait_event(root->deactivate_waitq, 50662306a36Sopenharmony_ci atomic_read(&kn->active) == KN_DEACTIVATED_BIAS); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (kernfs_lockdep(kn)) { 50962306a36Sopenharmony_ci lock_acquired(&kn->dep_map, _RET_IP_); 51062306a36Sopenharmony_ci rwsem_release(&kn->dep_map, _RET_IP_); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (kernfs_should_drain_open_files(kn)) 51462306a36Sopenharmony_ci kernfs_drain_open_files(kn); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/** 52062306a36Sopenharmony_ci * kernfs_get - get a reference count on a kernfs_node 52162306a36Sopenharmony_ci * @kn: the target kernfs_node 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_civoid kernfs_get(struct kernfs_node *kn) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci if (kn) { 52662306a36Sopenharmony_ci WARN_ON(!atomic_read(&kn->count)); 52762306a36Sopenharmony_ci atomic_inc(&kn->count); 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kernfs_get); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/** 53362306a36Sopenharmony_ci * kernfs_put - put a reference count on a kernfs_node 53462306a36Sopenharmony_ci * @kn: the target kernfs_node 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * Put a reference count of @kn and destroy it if it reached zero. 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_civoid kernfs_put(struct kernfs_node *kn) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct kernfs_node *parent; 54162306a36Sopenharmony_ci struct kernfs_root *root; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (!kn || !atomic_dec_and_test(&kn->count)) 54462306a36Sopenharmony_ci return; 54562306a36Sopenharmony_ci root = kernfs_root(kn); 54662306a36Sopenharmony_ci repeat: 54762306a36Sopenharmony_ci /* 54862306a36Sopenharmony_ci * Moving/renaming is always done while holding reference. 54962306a36Sopenharmony_ci * kn->parent won't change beneath us. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci parent = kn->parent; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, 55462306a36Sopenharmony_ci "kernfs_put: %s/%s: released with incorrect active_ref %d\n", 55562306a36Sopenharmony_ci parent ? parent->name : "", kn->name, atomic_read(&kn->active)); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (kernfs_type(kn) == KERNFS_LINK) 55862306a36Sopenharmony_ci kernfs_put(kn->symlink.target_kn); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci kfree_const(kn->name); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (kn->iattr) { 56362306a36Sopenharmony_ci simple_xattrs_free(&kn->iattr->xattrs, NULL); 56462306a36Sopenharmony_ci kmem_cache_free(kernfs_iattrs_cache, kn->iattr); 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci spin_lock(&kernfs_idr_lock); 56762306a36Sopenharmony_ci idr_remove(&root->ino_idr, (u32)kernfs_ino(kn)); 56862306a36Sopenharmony_ci spin_unlock(&kernfs_idr_lock); 56962306a36Sopenharmony_ci kmem_cache_free(kernfs_node_cache, kn); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci kn = parent; 57262306a36Sopenharmony_ci if (kn) { 57362306a36Sopenharmony_ci if (atomic_dec_and_test(&kn->count)) 57462306a36Sopenharmony_ci goto repeat; 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci /* just released the root kn, free @root too */ 57762306a36Sopenharmony_ci idr_destroy(&root->ino_idr); 57862306a36Sopenharmony_ci kfree(root); 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kernfs_put); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/** 58462306a36Sopenharmony_ci * kernfs_node_from_dentry - determine kernfs_node associated with a dentry 58562306a36Sopenharmony_ci * @dentry: the dentry in question 58662306a36Sopenharmony_ci * 58762306a36Sopenharmony_ci * Return: the kernfs_node associated with @dentry. If @dentry is not a 58862306a36Sopenharmony_ci * kernfs one, %NULL is returned. 58962306a36Sopenharmony_ci * 59062306a36Sopenharmony_ci * While the returned kernfs_node will stay accessible as long as @dentry 59162306a36Sopenharmony_ci * is accessible, the returned node can be in any state and the caller is 59262306a36Sopenharmony_ci * fully responsible for determining what's accessible. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_cistruct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci if (dentry->d_sb->s_op == &kernfs_sops) 59762306a36Sopenharmony_ci return kernfs_dentry_node(dentry); 59862306a36Sopenharmony_ci return NULL; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, 60262306a36Sopenharmony_ci struct kernfs_node *parent, 60362306a36Sopenharmony_ci const char *name, umode_t mode, 60462306a36Sopenharmony_ci kuid_t uid, kgid_t gid, 60562306a36Sopenharmony_ci unsigned flags) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct kernfs_node *kn; 60862306a36Sopenharmony_ci u32 id_highbits; 60962306a36Sopenharmony_ci int ret; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci name = kstrdup_const(name, GFP_KERNEL); 61262306a36Sopenharmony_ci if (!name) 61362306a36Sopenharmony_ci return NULL; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL); 61662306a36Sopenharmony_ci if (!kn) 61762306a36Sopenharmony_ci goto err_out1; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci idr_preload(GFP_KERNEL); 62062306a36Sopenharmony_ci spin_lock(&kernfs_idr_lock); 62162306a36Sopenharmony_ci ret = idr_alloc_cyclic(&root->ino_idr, kn, 1, 0, GFP_ATOMIC); 62262306a36Sopenharmony_ci if (ret >= 0 && ret < root->last_id_lowbits) 62362306a36Sopenharmony_ci root->id_highbits++; 62462306a36Sopenharmony_ci id_highbits = root->id_highbits; 62562306a36Sopenharmony_ci root->last_id_lowbits = ret; 62662306a36Sopenharmony_ci spin_unlock(&kernfs_idr_lock); 62762306a36Sopenharmony_ci idr_preload_end(); 62862306a36Sopenharmony_ci if (ret < 0) 62962306a36Sopenharmony_ci goto err_out2; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci kn->id = (u64)id_highbits << 32 | ret; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci atomic_set(&kn->count, 1); 63462306a36Sopenharmony_ci atomic_set(&kn->active, KN_DEACTIVATED_BIAS); 63562306a36Sopenharmony_ci RB_CLEAR_NODE(&kn->rb); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci kn->name = name; 63862306a36Sopenharmony_ci kn->mode = mode; 63962306a36Sopenharmony_ci kn->flags = flags; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (!uid_eq(uid, GLOBAL_ROOT_UID) || !gid_eq(gid, GLOBAL_ROOT_GID)) { 64262306a36Sopenharmony_ci struct iattr iattr = { 64362306a36Sopenharmony_ci .ia_valid = ATTR_UID | ATTR_GID, 64462306a36Sopenharmony_ci .ia_uid = uid, 64562306a36Sopenharmony_ci .ia_gid = gid, 64662306a36Sopenharmony_ci }; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci ret = __kernfs_setattr(kn, &iattr); 64962306a36Sopenharmony_ci if (ret < 0) 65062306a36Sopenharmony_ci goto err_out3; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (parent) { 65462306a36Sopenharmony_ci ret = security_kernfs_init_security(parent, kn); 65562306a36Sopenharmony_ci if (ret) 65662306a36Sopenharmony_ci goto err_out3; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci return kn; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci err_out3: 66262306a36Sopenharmony_ci spin_lock(&kernfs_idr_lock); 66362306a36Sopenharmony_ci idr_remove(&root->ino_idr, (u32)kernfs_ino(kn)); 66462306a36Sopenharmony_ci spin_unlock(&kernfs_idr_lock); 66562306a36Sopenharmony_ci err_out2: 66662306a36Sopenharmony_ci kmem_cache_free(kernfs_node_cache, kn); 66762306a36Sopenharmony_ci err_out1: 66862306a36Sopenharmony_ci kfree_const(name); 66962306a36Sopenharmony_ci return NULL; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistruct kernfs_node *kernfs_new_node(struct kernfs_node *parent, 67362306a36Sopenharmony_ci const char *name, umode_t mode, 67462306a36Sopenharmony_ci kuid_t uid, kgid_t gid, 67562306a36Sopenharmony_ci unsigned flags) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct kernfs_node *kn; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (parent->mode & S_ISGID) { 68062306a36Sopenharmony_ci /* this code block imitates inode_init_owner() for 68162306a36Sopenharmony_ci * kernfs 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (parent->iattr) 68562306a36Sopenharmony_ci gid = parent->iattr->ia_gid; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (flags & KERNFS_DIR) 68862306a36Sopenharmony_ci mode |= S_ISGID; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci kn = __kernfs_new_node(kernfs_root(parent), parent, 69262306a36Sopenharmony_ci name, mode, uid, gid, flags); 69362306a36Sopenharmony_ci if (kn) { 69462306a36Sopenharmony_ci kernfs_get(parent); 69562306a36Sopenharmony_ci kn->parent = parent; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci return kn; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci/* 70162306a36Sopenharmony_ci * kernfs_find_and_get_node_by_id - get kernfs_node from node id 70262306a36Sopenharmony_ci * @root: the kernfs root 70362306a36Sopenharmony_ci * @id: the target node id 70462306a36Sopenharmony_ci * 70562306a36Sopenharmony_ci * @id's lower 32bits encode ino and upper gen. If the gen portion is 70662306a36Sopenharmony_ci * zero, all generations are matched. 70762306a36Sopenharmony_ci * 70862306a36Sopenharmony_ci * Return: %NULL on failure, 70962306a36Sopenharmony_ci * otherwise a kernfs node with reference counter incremented. 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_cistruct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root, 71262306a36Sopenharmony_ci u64 id) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct kernfs_node *kn; 71562306a36Sopenharmony_ci ino_t ino = kernfs_id_ino(id); 71662306a36Sopenharmony_ci u32 gen = kernfs_id_gen(id); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci spin_lock(&kernfs_idr_lock); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci kn = idr_find(&root->ino_idr, (u32)ino); 72162306a36Sopenharmony_ci if (!kn) 72262306a36Sopenharmony_ci goto err_unlock; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (sizeof(ino_t) >= sizeof(u64)) { 72562306a36Sopenharmony_ci /* we looked up with the low 32bits, compare the whole */ 72662306a36Sopenharmony_ci if (kernfs_ino(kn) != ino) 72762306a36Sopenharmony_ci goto err_unlock; 72862306a36Sopenharmony_ci } else { 72962306a36Sopenharmony_ci /* 0 matches all generations */ 73062306a36Sopenharmony_ci if (unlikely(gen && kernfs_gen(kn) != gen)) 73162306a36Sopenharmony_ci goto err_unlock; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* 73562306a36Sopenharmony_ci * We should fail if @kn has never been activated and guarantee success 73662306a36Sopenharmony_ci * if the caller knows that @kn is active. Both can be achieved by 73762306a36Sopenharmony_ci * __kernfs_active() which tests @kn->active without kernfs_rwsem. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci if (unlikely(!__kernfs_active(kn) || !atomic_inc_not_zero(&kn->count))) 74062306a36Sopenharmony_ci goto err_unlock; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci spin_unlock(&kernfs_idr_lock); 74362306a36Sopenharmony_ci return kn; 74462306a36Sopenharmony_cierr_unlock: 74562306a36Sopenharmony_ci spin_unlock(&kernfs_idr_lock); 74662306a36Sopenharmony_ci return NULL; 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci/** 75062306a36Sopenharmony_ci * kernfs_add_one - add kernfs_node to parent without warning 75162306a36Sopenharmony_ci * @kn: kernfs_node to be added 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * The caller must already have initialized @kn->parent. This 75462306a36Sopenharmony_ci * function increments nlink of the parent's inode if @kn is a 75562306a36Sopenharmony_ci * directory and link into the children list of the parent. 75662306a36Sopenharmony_ci * 75762306a36Sopenharmony_ci * Return: 75862306a36Sopenharmony_ci * %0 on success, -EEXIST if entry with the given name already 75962306a36Sopenharmony_ci * exists. 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_ciint kernfs_add_one(struct kernfs_node *kn) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci struct kernfs_node *parent = kn->parent; 76462306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(parent); 76562306a36Sopenharmony_ci struct kernfs_iattrs *ps_iattr; 76662306a36Sopenharmony_ci bool has_ns; 76762306a36Sopenharmony_ci int ret; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci ret = -EINVAL; 77262306a36Sopenharmony_ci has_ns = kernfs_ns_enabled(parent); 77362306a36Sopenharmony_ci if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 77462306a36Sopenharmony_ci has_ns ? "required" : "invalid", parent->name, kn->name)) 77562306a36Sopenharmony_ci goto out_unlock; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (kernfs_type(parent) != KERNFS_DIR) 77862306a36Sopenharmony_ci goto out_unlock; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci ret = -ENOENT; 78162306a36Sopenharmony_ci if (parent->flags & (KERNFS_REMOVING | KERNFS_EMPTY_DIR)) 78262306a36Sopenharmony_ci goto out_unlock; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci kn->hash = kernfs_name_hash(kn->name, kn->ns); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci ret = kernfs_link_sibling(kn); 78762306a36Sopenharmony_ci if (ret) 78862306a36Sopenharmony_ci goto out_unlock; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* Update timestamps on the parent */ 79162306a36Sopenharmony_ci down_write(&root->kernfs_iattr_rwsem); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci ps_iattr = parent->iattr; 79462306a36Sopenharmony_ci if (ps_iattr) { 79562306a36Sopenharmony_ci ktime_get_real_ts64(&ps_iattr->ia_ctime); 79662306a36Sopenharmony_ci ps_iattr->ia_mtime = ps_iattr->ia_ctime; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci up_write(&root->kernfs_iattr_rwsem); 80062306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* 80362306a36Sopenharmony_ci * Activate the new node unless CREATE_DEACTIVATED is requested. 80462306a36Sopenharmony_ci * If not activated here, the kernfs user is responsible for 80562306a36Sopenharmony_ci * activating the node with kernfs_activate(). A node which hasn't 80662306a36Sopenharmony_ci * been activated is not visible to userland and its removal won't 80762306a36Sopenharmony_ci * trigger deactivation. 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_ci if (!(kernfs_root(kn)->flags & KERNFS_ROOT_CREATE_DEACTIVATED)) 81062306a36Sopenharmony_ci kernfs_activate(kn); 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ciout_unlock: 81462306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 81562306a36Sopenharmony_ci return ret; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci/** 81962306a36Sopenharmony_ci * kernfs_find_ns - find kernfs_node with the given name 82062306a36Sopenharmony_ci * @parent: kernfs_node to search under 82162306a36Sopenharmony_ci * @name: name to look for 82262306a36Sopenharmony_ci * @ns: the namespace tag to use 82362306a36Sopenharmony_ci * 82462306a36Sopenharmony_ci * Look for kernfs_node with name @name under @parent. 82562306a36Sopenharmony_ci * 82662306a36Sopenharmony_ci * Return: pointer to the found kernfs_node on success, %NULL on failure. 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_cistatic struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, 82962306a36Sopenharmony_ci const unsigned char *name, 83062306a36Sopenharmony_ci const void *ns) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct rb_node *node = parent->dir.children.rb_node; 83362306a36Sopenharmony_ci bool has_ns = kernfs_ns_enabled(parent); 83462306a36Sopenharmony_ci unsigned int hash; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci lockdep_assert_held(&kernfs_root(parent)->kernfs_rwsem); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (has_ns != (bool)ns) { 83962306a36Sopenharmony_ci WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 84062306a36Sopenharmony_ci has_ns ? "required" : "invalid", parent->name, name); 84162306a36Sopenharmony_ci return NULL; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci hash = kernfs_name_hash(name, ns); 84562306a36Sopenharmony_ci while (node) { 84662306a36Sopenharmony_ci struct kernfs_node *kn; 84762306a36Sopenharmony_ci int result; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci kn = rb_to_kn(node); 85062306a36Sopenharmony_ci result = kernfs_name_compare(hash, name, ns, kn); 85162306a36Sopenharmony_ci if (result < 0) 85262306a36Sopenharmony_ci node = node->rb_left; 85362306a36Sopenharmony_ci else if (result > 0) 85462306a36Sopenharmony_ci node = node->rb_right; 85562306a36Sopenharmony_ci else 85662306a36Sopenharmony_ci return kn; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci return NULL; 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent, 86262306a36Sopenharmony_ci const unsigned char *path, 86362306a36Sopenharmony_ci const void *ns) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci size_t len; 86662306a36Sopenharmony_ci char *p, *name; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci lockdep_assert_held_read(&kernfs_root(parent)->kernfs_rwsem); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci spin_lock_irq(&kernfs_pr_cont_lock); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci len = strlcpy(kernfs_pr_cont_buf, path, sizeof(kernfs_pr_cont_buf)); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (len >= sizeof(kernfs_pr_cont_buf)) { 87562306a36Sopenharmony_ci spin_unlock_irq(&kernfs_pr_cont_lock); 87662306a36Sopenharmony_ci return NULL; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci p = kernfs_pr_cont_buf; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci while ((name = strsep(&p, "/")) && parent) { 88262306a36Sopenharmony_ci if (*name == '\0') 88362306a36Sopenharmony_ci continue; 88462306a36Sopenharmony_ci parent = kernfs_find_ns(parent, name, ns); 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci spin_unlock_irq(&kernfs_pr_cont_lock); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return parent; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci/** 89362306a36Sopenharmony_ci * kernfs_find_and_get_ns - find and get kernfs_node with the given name 89462306a36Sopenharmony_ci * @parent: kernfs_node to search under 89562306a36Sopenharmony_ci * @name: name to look for 89662306a36Sopenharmony_ci * @ns: the namespace tag to use 89762306a36Sopenharmony_ci * 89862306a36Sopenharmony_ci * Look for kernfs_node with name @name under @parent and get a reference 89962306a36Sopenharmony_ci * if found. This function may sleep. 90062306a36Sopenharmony_ci * 90162306a36Sopenharmony_ci * Return: pointer to the found kernfs_node on success, %NULL on failure. 90262306a36Sopenharmony_ci */ 90362306a36Sopenharmony_cistruct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, 90462306a36Sopenharmony_ci const char *name, const void *ns) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct kernfs_node *kn; 90762306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(parent); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci down_read(&root->kernfs_rwsem); 91062306a36Sopenharmony_ci kn = kernfs_find_ns(parent, name, ns); 91162306a36Sopenharmony_ci kernfs_get(kn); 91262306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci return kn; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci/** 91962306a36Sopenharmony_ci * kernfs_walk_and_get_ns - find and get kernfs_node with the given path 92062306a36Sopenharmony_ci * @parent: kernfs_node to search under 92162306a36Sopenharmony_ci * @path: path to look for 92262306a36Sopenharmony_ci * @ns: the namespace tag to use 92362306a36Sopenharmony_ci * 92462306a36Sopenharmony_ci * Look for kernfs_node with path @path under @parent and get a reference 92562306a36Sopenharmony_ci * if found. This function may sleep. 92662306a36Sopenharmony_ci * 92762306a36Sopenharmony_ci * Return: pointer to the found kernfs_node on success, %NULL on failure. 92862306a36Sopenharmony_ci */ 92962306a36Sopenharmony_cistruct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, 93062306a36Sopenharmony_ci const char *path, const void *ns) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci struct kernfs_node *kn; 93362306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(parent); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci down_read(&root->kernfs_rwsem); 93662306a36Sopenharmony_ci kn = kernfs_walk_ns(parent, path, ns); 93762306a36Sopenharmony_ci kernfs_get(kn); 93862306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return kn; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/** 94462306a36Sopenharmony_ci * kernfs_create_root - create a new kernfs hierarchy 94562306a36Sopenharmony_ci * @scops: optional syscall operations for the hierarchy 94662306a36Sopenharmony_ci * @flags: KERNFS_ROOT_* flags 94762306a36Sopenharmony_ci * @priv: opaque data associated with the new directory 94862306a36Sopenharmony_ci * 94962306a36Sopenharmony_ci * Return: the root of the new hierarchy on success, ERR_PTR() value on 95062306a36Sopenharmony_ci * failure. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_cistruct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, 95362306a36Sopenharmony_ci unsigned int flags, void *priv) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci struct kernfs_root *root; 95662306a36Sopenharmony_ci struct kernfs_node *kn; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci root = kzalloc(sizeof(*root), GFP_KERNEL); 95962306a36Sopenharmony_ci if (!root) 96062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci idr_init(&root->ino_idr); 96362306a36Sopenharmony_ci init_rwsem(&root->kernfs_rwsem); 96462306a36Sopenharmony_ci init_rwsem(&root->kernfs_iattr_rwsem); 96562306a36Sopenharmony_ci init_rwsem(&root->kernfs_supers_rwsem); 96662306a36Sopenharmony_ci INIT_LIST_HEAD(&root->supers); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* 96962306a36Sopenharmony_ci * On 64bit ino setups, id is ino. On 32bit, low 32bits are ino. 97062306a36Sopenharmony_ci * High bits generation. The starting value for both ino and 97162306a36Sopenharmony_ci * genenration is 1. Initialize upper 32bit allocation 97262306a36Sopenharmony_ci * accordingly. 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ci if (sizeof(ino_t) >= sizeof(u64)) 97562306a36Sopenharmony_ci root->id_highbits = 0; 97662306a36Sopenharmony_ci else 97762306a36Sopenharmony_ci root->id_highbits = 1; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci kn = __kernfs_new_node(root, NULL, "", S_IFDIR | S_IRUGO | S_IXUGO, 98062306a36Sopenharmony_ci GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 98162306a36Sopenharmony_ci KERNFS_DIR); 98262306a36Sopenharmony_ci if (!kn) { 98362306a36Sopenharmony_ci idr_destroy(&root->ino_idr); 98462306a36Sopenharmony_ci kfree(root); 98562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci kn->priv = priv; 98962306a36Sopenharmony_ci kn->dir.root = root; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci root->syscall_ops = scops; 99262306a36Sopenharmony_ci root->flags = flags; 99362306a36Sopenharmony_ci root->kn = kn; 99462306a36Sopenharmony_ci init_waitqueue_head(&root->deactivate_waitq); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED)) 99762306a36Sopenharmony_ci kernfs_activate(kn); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci return root; 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci/** 100362306a36Sopenharmony_ci * kernfs_destroy_root - destroy a kernfs hierarchy 100462306a36Sopenharmony_ci * @root: root of the hierarchy to destroy 100562306a36Sopenharmony_ci * 100662306a36Sopenharmony_ci * Destroy the hierarchy anchored at @root by removing all existing 100762306a36Sopenharmony_ci * directories and destroying @root. 100862306a36Sopenharmony_ci */ 100962306a36Sopenharmony_civoid kernfs_destroy_root(struct kernfs_root *root) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci /* 101262306a36Sopenharmony_ci * kernfs_remove holds kernfs_rwsem from the root so the root 101362306a36Sopenharmony_ci * shouldn't be freed during the operation. 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_ci kernfs_get(root->kn); 101662306a36Sopenharmony_ci kernfs_remove(root->kn); 101762306a36Sopenharmony_ci kernfs_put(root->kn); /* will also free @root */ 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci/** 102162306a36Sopenharmony_ci * kernfs_root_to_node - return the kernfs_node associated with a kernfs_root 102262306a36Sopenharmony_ci * @root: root to use to lookup 102362306a36Sopenharmony_ci * 102462306a36Sopenharmony_ci * Return: @root's kernfs_node 102562306a36Sopenharmony_ci */ 102662306a36Sopenharmony_cistruct kernfs_node *kernfs_root_to_node(struct kernfs_root *root) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci return root->kn; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci/** 103262306a36Sopenharmony_ci * kernfs_create_dir_ns - create a directory 103362306a36Sopenharmony_ci * @parent: parent in which to create a new directory 103462306a36Sopenharmony_ci * @name: name of the new directory 103562306a36Sopenharmony_ci * @mode: mode of the new directory 103662306a36Sopenharmony_ci * @uid: uid of the new directory 103762306a36Sopenharmony_ci * @gid: gid of the new directory 103862306a36Sopenharmony_ci * @priv: opaque data associated with the new directory 103962306a36Sopenharmony_ci * @ns: optional namespace tag of the directory 104062306a36Sopenharmony_ci * 104162306a36Sopenharmony_ci * Return: the created node on success, ERR_PTR() value on failure. 104262306a36Sopenharmony_ci */ 104362306a36Sopenharmony_cistruct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, 104462306a36Sopenharmony_ci const char *name, umode_t mode, 104562306a36Sopenharmony_ci kuid_t uid, kgid_t gid, 104662306a36Sopenharmony_ci void *priv, const void *ns) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci struct kernfs_node *kn; 104962306a36Sopenharmony_ci int rc; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* allocate */ 105262306a36Sopenharmony_ci kn = kernfs_new_node(parent, name, mode | S_IFDIR, 105362306a36Sopenharmony_ci uid, gid, KERNFS_DIR); 105462306a36Sopenharmony_ci if (!kn) 105562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci kn->dir.root = parent->dir.root; 105862306a36Sopenharmony_ci kn->ns = ns; 105962306a36Sopenharmony_ci kn->priv = priv; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* link in */ 106262306a36Sopenharmony_ci rc = kernfs_add_one(kn); 106362306a36Sopenharmony_ci if (!rc) 106462306a36Sopenharmony_ci return kn; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci kernfs_put(kn); 106762306a36Sopenharmony_ci return ERR_PTR(rc); 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci/** 107162306a36Sopenharmony_ci * kernfs_create_empty_dir - create an always empty directory 107262306a36Sopenharmony_ci * @parent: parent in which to create a new directory 107362306a36Sopenharmony_ci * @name: name of the new directory 107462306a36Sopenharmony_ci * 107562306a36Sopenharmony_ci * Return: the created node on success, ERR_PTR() value on failure. 107662306a36Sopenharmony_ci */ 107762306a36Sopenharmony_cistruct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, 107862306a36Sopenharmony_ci const char *name) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci struct kernfs_node *kn; 108162306a36Sopenharmony_ci int rc; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* allocate */ 108462306a36Sopenharmony_ci kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR, 108562306a36Sopenharmony_ci GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, KERNFS_DIR); 108662306a36Sopenharmony_ci if (!kn) 108762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci kn->flags |= KERNFS_EMPTY_DIR; 109062306a36Sopenharmony_ci kn->dir.root = parent->dir.root; 109162306a36Sopenharmony_ci kn->ns = NULL; 109262306a36Sopenharmony_ci kn->priv = NULL; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* link in */ 109562306a36Sopenharmony_ci rc = kernfs_add_one(kn); 109662306a36Sopenharmony_ci if (!rc) 109762306a36Sopenharmony_ci return kn; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci kernfs_put(kn); 110062306a36Sopenharmony_ci return ERR_PTR(rc); 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci struct kernfs_node *kn; 110662306a36Sopenharmony_ci struct kernfs_root *root; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (flags & LOOKUP_RCU) 110962306a36Sopenharmony_ci return -ECHILD; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* Negative hashed dentry? */ 111262306a36Sopenharmony_ci if (d_really_is_negative(dentry)) { 111362306a36Sopenharmony_ci struct kernfs_node *parent; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* If the kernfs parent node has changed discard and 111662306a36Sopenharmony_ci * proceed to ->lookup. 111762306a36Sopenharmony_ci * 111862306a36Sopenharmony_ci * There's nothing special needed here when getting the 111962306a36Sopenharmony_ci * dentry parent, even if a concurrent rename is in 112062306a36Sopenharmony_ci * progress. That's because the dentry is negative so 112162306a36Sopenharmony_ci * it can only be the target of the rename and it will 112262306a36Sopenharmony_ci * be doing a d_move() not a replace. Consequently the 112362306a36Sopenharmony_ci * dentry d_parent won't change over the d_move(). 112462306a36Sopenharmony_ci * 112562306a36Sopenharmony_ci * Also kernfs negative dentries transitioning from 112662306a36Sopenharmony_ci * negative to positive during revalidate won't happen 112762306a36Sopenharmony_ci * because they are invalidated on containing directory 112862306a36Sopenharmony_ci * changes and the lookup re-done so that a new positive 112962306a36Sopenharmony_ci * dentry can be properly created. 113062306a36Sopenharmony_ci */ 113162306a36Sopenharmony_ci root = kernfs_root_from_sb(dentry->d_sb); 113262306a36Sopenharmony_ci down_read(&root->kernfs_rwsem); 113362306a36Sopenharmony_ci parent = kernfs_dentry_node(dentry->d_parent); 113462306a36Sopenharmony_ci if (parent) { 113562306a36Sopenharmony_ci if (kernfs_dir_changed(parent, dentry)) { 113662306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 113762306a36Sopenharmony_ci return 0; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci /* The kernfs parent node hasn't changed, leave the 114362306a36Sopenharmony_ci * dentry negative and return success. 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_ci return 1; 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci kn = kernfs_dentry_node(dentry); 114962306a36Sopenharmony_ci root = kernfs_root(kn); 115062306a36Sopenharmony_ci down_read(&root->kernfs_rwsem); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci /* The kernfs node has been deactivated */ 115362306a36Sopenharmony_ci if (!kernfs_active(kn)) 115462306a36Sopenharmony_ci goto out_bad; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* The kernfs node has been moved? */ 115762306a36Sopenharmony_ci if (kernfs_dentry_node(dentry->d_parent) != kn->parent) 115862306a36Sopenharmony_ci goto out_bad; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci /* The kernfs node has been renamed */ 116162306a36Sopenharmony_ci if (strcmp(dentry->d_name.name, kn->name) != 0) 116262306a36Sopenharmony_ci goto out_bad; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* The kernfs node has been moved to a different namespace */ 116562306a36Sopenharmony_ci if (kn->parent && kernfs_ns_enabled(kn->parent) && 116662306a36Sopenharmony_ci kernfs_info(dentry->d_sb)->ns != kn->ns) 116762306a36Sopenharmony_ci goto out_bad; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 117062306a36Sopenharmony_ci return 1; 117162306a36Sopenharmony_ciout_bad: 117262306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 117362306a36Sopenharmony_ci return 0; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ciconst struct dentry_operations kernfs_dops = { 117762306a36Sopenharmony_ci .d_revalidate = kernfs_dop_revalidate, 117862306a36Sopenharmony_ci}; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic struct dentry *kernfs_iop_lookup(struct inode *dir, 118162306a36Sopenharmony_ci struct dentry *dentry, 118262306a36Sopenharmony_ci unsigned int flags) 118362306a36Sopenharmony_ci{ 118462306a36Sopenharmony_ci struct kernfs_node *parent = dir->i_private; 118562306a36Sopenharmony_ci struct kernfs_node *kn; 118662306a36Sopenharmony_ci struct kernfs_root *root; 118762306a36Sopenharmony_ci struct inode *inode = NULL; 118862306a36Sopenharmony_ci const void *ns = NULL; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci root = kernfs_root(parent); 119162306a36Sopenharmony_ci down_read(&root->kernfs_rwsem); 119262306a36Sopenharmony_ci if (kernfs_ns_enabled(parent)) 119362306a36Sopenharmony_ci ns = kernfs_info(dir->i_sb)->ns; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci kn = kernfs_find_ns(parent, dentry->d_name.name, ns); 119662306a36Sopenharmony_ci /* attach dentry and inode */ 119762306a36Sopenharmony_ci if (kn) { 119862306a36Sopenharmony_ci /* Inactive nodes are invisible to the VFS so don't 119962306a36Sopenharmony_ci * create a negative. 120062306a36Sopenharmony_ci */ 120162306a36Sopenharmony_ci if (!kernfs_active(kn)) { 120262306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 120362306a36Sopenharmony_ci return NULL; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci inode = kernfs_get_inode(dir->i_sb, kn); 120662306a36Sopenharmony_ci if (!inode) 120762306a36Sopenharmony_ci inode = ERR_PTR(-ENOMEM); 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci /* 121062306a36Sopenharmony_ci * Needed for negative dentry validation. 121162306a36Sopenharmony_ci * The negative dentry can be created in kernfs_iop_lookup() 121262306a36Sopenharmony_ci * or transforms from positive dentry in dentry_unlink_inode() 121362306a36Sopenharmony_ci * called from vfs_rmdir(). 121462306a36Sopenharmony_ci */ 121562306a36Sopenharmony_ci if (!IS_ERR(inode)) 121662306a36Sopenharmony_ci kernfs_set_rev(parent, dentry); 121762306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci /* instantiate and hash (possibly negative) dentry */ 122062306a36Sopenharmony_ci return d_splice_alias(inode, dentry); 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic int kernfs_iop_mkdir(struct mnt_idmap *idmap, 122462306a36Sopenharmony_ci struct inode *dir, struct dentry *dentry, 122562306a36Sopenharmony_ci umode_t mode) 122662306a36Sopenharmony_ci{ 122762306a36Sopenharmony_ci struct kernfs_node *parent = dir->i_private; 122862306a36Sopenharmony_ci struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops; 122962306a36Sopenharmony_ci int ret; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (!scops || !scops->mkdir) 123262306a36Sopenharmony_ci return -EPERM; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci if (!kernfs_get_active(parent)) 123562306a36Sopenharmony_ci return -ENODEV; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci ret = scops->mkdir(parent, dentry->d_name.name, mode); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci kernfs_put_active(parent); 124062306a36Sopenharmony_ci return ret; 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cistatic int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) 124462306a36Sopenharmony_ci{ 124562306a36Sopenharmony_ci struct kernfs_node *kn = kernfs_dentry_node(dentry); 124662306a36Sopenharmony_ci struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops; 124762306a36Sopenharmony_ci int ret; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (!scops || !scops->rmdir) 125062306a36Sopenharmony_ci return -EPERM; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (!kernfs_get_active(kn)) 125362306a36Sopenharmony_ci return -ENODEV; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci ret = scops->rmdir(kn); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci kernfs_put_active(kn); 125862306a36Sopenharmony_ci return ret; 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_cistatic int kernfs_iop_rename(struct mnt_idmap *idmap, 126262306a36Sopenharmony_ci struct inode *old_dir, struct dentry *old_dentry, 126362306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 126462306a36Sopenharmony_ci unsigned int flags) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci struct kernfs_node *kn = kernfs_dentry_node(old_dentry); 126762306a36Sopenharmony_ci struct kernfs_node *new_parent = new_dir->i_private; 126862306a36Sopenharmony_ci struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops; 126962306a36Sopenharmony_ci int ret; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci if (flags) 127262306a36Sopenharmony_ci return -EINVAL; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci if (!scops || !scops->rename) 127562306a36Sopenharmony_ci return -EPERM; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci if (!kernfs_get_active(kn)) 127862306a36Sopenharmony_ci return -ENODEV; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (!kernfs_get_active(new_parent)) { 128162306a36Sopenharmony_ci kernfs_put_active(kn); 128262306a36Sopenharmony_ci return -ENODEV; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci ret = scops->rename(kn, new_parent, new_dentry->d_name.name); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci kernfs_put_active(new_parent); 128862306a36Sopenharmony_ci kernfs_put_active(kn); 128962306a36Sopenharmony_ci return ret; 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ciconst struct inode_operations kernfs_dir_iops = { 129362306a36Sopenharmony_ci .lookup = kernfs_iop_lookup, 129462306a36Sopenharmony_ci .permission = kernfs_iop_permission, 129562306a36Sopenharmony_ci .setattr = kernfs_iop_setattr, 129662306a36Sopenharmony_ci .getattr = kernfs_iop_getattr, 129762306a36Sopenharmony_ci .listxattr = kernfs_iop_listxattr, 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci .mkdir = kernfs_iop_mkdir, 130062306a36Sopenharmony_ci .rmdir = kernfs_iop_rmdir, 130162306a36Sopenharmony_ci .rename = kernfs_iop_rename, 130262306a36Sopenharmony_ci}; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cistatic struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci struct kernfs_node *last; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci while (true) { 130962306a36Sopenharmony_ci struct rb_node *rbn; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci last = pos; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (kernfs_type(pos) != KERNFS_DIR) 131462306a36Sopenharmony_ci break; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci rbn = rb_first(&pos->dir.children); 131762306a36Sopenharmony_ci if (!rbn) 131862306a36Sopenharmony_ci break; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci pos = rb_to_kn(rbn); 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci return last; 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci/** 132762306a36Sopenharmony_ci * kernfs_next_descendant_post - find the next descendant for post-order walk 132862306a36Sopenharmony_ci * @pos: the current position (%NULL to initiate traversal) 132962306a36Sopenharmony_ci * @root: kernfs_node whose descendants to walk 133062306a36Sopenharmony_ci * 133162306a36Sopenharmony_ci * Find the next descendant to visit for post-order traversal of @root's 133262306a36Sopenharmony_ci * descendants. @root is included in the iteration and the last node to be 133362306a36Sopenharmony_ci * visited. 133462306a36Sopenharmony_ci * 133562306a36Sopenharmony_ci * Return: the next descendant to visit or %NULL when done. 133662306a36Sopenharmony_ci */ 133762306a36Sopenharmony_cistatic struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, 133862306a36Sopenharmony_ci struct kernfs_node *root) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci struct rb_node *rbn; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci lockdep_assert_held_write(&kernfs_root(root)->kernfs_rwsem); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci /* if first iteration, visit leftmost descendant which may be root */ 134562306a36Sopenharmony_ci if (!pos) 134662306a36Sopenharmony_ci return kernfs_leftmost_descendant(root); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* if we visited @root, we're done */ 134962306a36Sopenharmony_ci if (pos == root) 135062306a36Sopenharmony_ci return NULL; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* if there's an unvisited sibling, visit its leftmost descendant */ 135362306a36Sopenharmony_ci rbn = rb_next(&pos->rb); 135462306a36Sopenharmony_ci if (rbn) 135562306a36Sopenharmony_ci return kernfs_leftmost_descendant(rb_to_kn(rbn)); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* no sibling left, visit parent */ 135862306a36Sopenharmony_ci return pos->parent; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic void kernfs_activate_one(struct kernfs_node *kn) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci lockdep_assert_held_write(&kernfs_root(kn)->kernfs_rwsem); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci kn->flags |= KERNFS_ACTIVATED; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (kernfs_active(kn) || (kn->flags & (KERNFS_HIDDEN | KERNFS_REMOVING))) 136862306a36Sopenharmony_ci return; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci WARN_ON_ONCE(kn->parent && RB_EMPTY_NODE(&kn->rb)); 137162306a36Sopenharmony_ci WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci atomic_sub(KN_DEACTIVATED_BIAS, &kn->active); 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci/** 137762306a36Sopenharmony_ci * kernfs_activate - activate a node which started deactivated 137862306a36Sopenharmony_ci * @kn: kernfs_node whose subtree is to be activated 137962306a36Sopenharmony_ci * 138062306a36Sopenharmony_ci * If the root has KERNFS_ROOT_CREATE_DEACTIVATED set, a newly created node 138162306a36Sopenharmony_ci * needs to be explicitly activated. A node which hasn't been activated 138262306a36Sopenharmony_ci * isn't visible to userland and deactivation is skipped during its 138362306a36Sopenharmony_ci * removal. This is useful to construct atomic init sequences where 138462306a36Sopenharmony_ci * creation of multiple nodes should either succeed or fail atomically. 138562306a36Sopenharmony_ci * 138662306a36Sopenharmony_ci * The caller is responsible for ensuring that this function is not called 138762306a36Sopenharmony_ci * after kernfs_remove*() is invoked on @kn. 138862306a36Sopenharmony_ci */ 138962306a36Sopenharmony_civoid kernfs_activate(struct kernfs_node *kn) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci struct kernfs_node *pos; 139262306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(kn); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci pos = NULL; 139762306a36Sopenharmony_ci while ((pos = kernfs_next_descendant_post(pos, kn))) 139862306a36Sopenharmony_ci kernfs_activate_one(pos); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 140162306a36Sopenharmony_ci} 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci/** 140462306a36Sopenharmony_ci * kernfs_show - show or hide a node 140562306a36Sopenharmony_ci * @kn: kernfs_node to show or hide 140662306a36Sopenharmony_ci * @show: whether to show or hide 140762306a36Sopenharmony_ci * 140862306a36Sopenharmony_ci * If @show is %false, @kn is marked hidden and deactivated. A hidden node is 140962306a36Sopenharmony_ci * ignored in future activaitons. If %true, the mark is removed and activation 141062306a36Sopenharmony_ci * state is restored. This function won't implicitly activate a new node in a 141162306a36Sopenharmony_ci * %KERNFS_ROOT_CREATE_DEACTIVATED root which hasn't been activated yet. 141262306a36Sopenharmony_ci * 141362306a36Sopenharmony_ci * To avoid recursion complexities, directories aren't supported for now. 141462306a36Sopenharmony_ci */ 141562306a36Sopenharmony_civoid kernfs_show(struct kernfs_node *kn, bool show) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(kn); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci if (WARN_ON_ONCE(kernfs_type(kn) == KERNFS_DIR)) 142062306a36Sopenharmony_ci return; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci if (show) { 142562306a36Sopenharmony_ci kn->flags &= ~KERNFS_HIDDEN; 142662306a36Sopenharmony_ci if (kn->flags & KERNFS_ACTIVATED) 142762306a36Sopenharmony_ci kernfs_activate_one(kn); 142862306a36Sopenharmony_ci } else { 142962306a36Sopenharmony_ci kn->flags |= KERNFS_HIDDEN; 143062306a36Sopenharmony_ci if (kernfs_active(kn)) 143162306a36Sopenharmony_ci atomic_add(KN_DEACTIVATED_BIAS, &kn->active); 143262306a36Sopenharmony_ci kernfs_drain(kn); 143362306a36Sopenharmony_ci } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic void __kernfs_remove(struct kernfs_node *kn) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci struct kernfs_node *pos; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci /* Short-circuit if non-root @kn has already finished removal. */ 144362306a36Sopenharmony_ci if (!kn) 144462306a36Sopenharmony_ci return; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci lockdep_assert_held_write(&kernfs_root(kn)->kernfs_rwsem); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* 144962306a36Sopenharmony_ci * This is for kernfs_remove_self() which plays with active ref 145062306a36Sopenharmony_ci * after removal. 145162306a36Sopenharmony_ci */ 145262306a36Sopenharmony_ci if (kn->parent && RB_EMPTY_NODE(&kn->rb)) 145362306a36Sopenharmony_ci return; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci pr_debug("kernfs %s: removing\n", kn->name); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* prevent new usage by marking all nodes removing and deactivating */ 145862306a36Sopenharmony_ci pos = NULL; 145962306a36Sopenharmony_ci while ((pos = kernfs_next_descendant_post(pos, kn))) { 146062306a36Sopenharmony_ci pos->flags |= KERNFS_REMOVING; 146162306a36Sopenharmony_ci if (kernfs_active(pos)) 146262306a36Sopenharmony_ci atomic_add(KN_DEACTIVATED_BIAS, &pos->active); 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci /* deactivate and unlink the subtree node-by-node */ 146662306a36Sopenharmony_ci do { 146762306a36Sopenharmony_ci pos = kernfs_leftmost_descendant(kn); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci /* 147062306a36Sopenharmony_ci * kernfs_drain() may drop kernfs_rwsem temporarily and @pos's 147162306a36Sopenharmony_ci * base ref could have been put by someone else by the time 147262306a36Sopenharmony_ci * the function returns. Make sure it doesn't go away 147362306a36Sopenharmony_ci * underneath us. 147462306a36Sopenharmony_ci */ 147562306a36Sopenharmony_ci kernfs_get(pos); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci kernfs_drain(pos); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci /* 148062306a36Sopenharmony_ci * kernfs_unlink_sibling() succeeds once per node. Use it 148162306a36Sopenharmony_ci * to decide who's responsible for cleanups. 148262306a36Sopenharmony_ci */ 148362306a36Sopenharmony_ci if (!pos->parent || kernfs_unlink_sibling(pos)) { 148462306a36Sopenharmony_ci struct kernfs_iattrs *ps_iattr = 148562306a36Sopenharmony_ci pos->parent ? pos->parent->iattr : NULL; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* update timestamps on the parent */ 148862306a36Sopenharmony_ci down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci if (ps_iattr) { 149162306a36Sopenharmony_ci ktime_get_real_ts64(&ps_iattr->ia_ctime); 149262306a36Sopenharmony_ci ps_iattr->ia_mtime = ps_iattr->ia_ctime; 149362306a36Sopenharmony_ci } 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); 149662306a36Sopenharmony_ci kernfs_put(pos); 149762306a36Sopenharmony_ci } 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci kernfs_put(pos); 150062306a36Sopenharmony_ci } while (pos != kn); 150162306a36Sopenharmony_ci} 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci/** 150462306a36Sopenharmony_ci * kernfs_remove - remove a kernfs_node recursively 150562306a36Sopenharmony_ci * @kn: the kernfs_node to remove 150662306a36Sopenharmony_ci * 150762306a36Sopenharmony_ci * Remove @kn along with all its subdirectories and files. 150862306a36Sopenharmony_ci */ 150962306a36Sopenharmony_civoid kernfs_remove(struct kernfs_node *kn) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci struct kernfs_root *root; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci if (!kn) 151462306a36Sopenharmony_ci return; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci root = kernfs_root(kn); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 151962306a36Sopenharmony_ci __kernfs_remove(kn); 152062306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci/** 152462306a36Sopenharmony_ci * kernfs_break_active_protection - break out of active protection 152562306a36Sopenharmony_ci * @kn: the self kernfs_node 152662306a36Sopenharmony_ci * 152762306a36Sopenharmony_ci * The caller must be running off of a kernfs operation which is invoked 152862306a36Sopenharmony_ci * with an active reference - e.g. one of kernfs_ops. Each invocation of 152962306a36Sopenharmony_ci * this function must also be matched with an invocation of 153062306a36Sopenharmony_ci * kernfs_unbreak_active_protection(). 153162306a36Sopenharmony_ci * 153262306a36Sopenharmony_ci * This function releases the active reference of @kn the caller is 153362306a36Sopenharmony_ci * holding. Once this function is called, @kn may be removed at any point 153462306a36Sopenharmony_ci * and the caller is solely responsible for ensuring that the objects it 153562306a36Sopenharmony_ci * dereferences are accessible. 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_civoid kernfs_break_active_protection(struct kernfs_node *kn) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci /* 154062306a36Sopenharmony_ci * Take out ourself out of the active ref dependency chain. If 154162306a36Sopenharmony_ci * we're called without an active ref, lockdep will complain. 154262306a36Sopenharmony_ci */ 154362306a36Sopenharmony_ci kernfs_put_active(kn); 154462306a36Sopenharmony_ci} 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci/** 154762306a36Sopenharmony_ci * kernfs_unbreak_active_protection - undo kernfs_break_active_protection() 154862306a36Sopenharmony_ci * @kn: the self kernfs_node 154962306a36Sopenharmony_ci * 155062306a36Sopenharmony_ci * If kernfs_break_active_protection() was called, this function must be 155162306a36Sopenharmony_ci * invoked before finishing the kernfs operation. Note that while this 155262306a36Sopenharmony_ci * function restores the active reference, it doesn't and can't actually 155362306a36Sopenharmony_ci * restore the active protection - @kn may already or be in the process of 155462306a36Sopenharmony_ci * being removed. Once kernfs_break_active_protection() is invoked, that 155562306a36Sopenharmony_ci * protection is irreversibly gone for the kernfs operation instance. 155662306a36Sopenharmony_ci * 155762306a36Sopenharmony_ci * While this function may be called at any point after 155862306a36Sopenharmony_ci * kernfs_break_active_protection() is invoked, its most useful location 155962306a36Sopenharmony_ci * would be right before the enclosing kernfs operation returns. 156062306a36Sopenharmony_ci */ 156162306a36Sopenharmony_civoid kernfs_unbreak_active_protection(struct kernfs_node *kn) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci /* 156462306a36Sopenharmony_ci * @kn->active could be in any state; however, the increment we do 156562306a36Sopenharmony_ci * here will be undone as soon as the enclosing kernfs operation 156662306a36Sopenharmony_ci * finishes and this temporary bump can't break anything. If @kn 156762306a36Sopenharmony_ci * is alive, nothing changes. If @kn is being deactivated, the 156862306a36Sopenharmony_ci * soon-to-follow put will either finish deactivation or restore 156962306a36Sopenharmony_ci * deactivated state. If @kn is already removed, the temporary 157062306a36Sopenharmony_ci * bump is guaranteed to be gone before @kn is released. 157162306a36Sopenharmony_ci */ 157262306a36Sopenharmony_ci atomic_inc(&kn->active); 157362306a36Sopenharmony_ci if (kernfs_lockdep(kn)) 157462306a36Sopenharmony_ci rwsem_acquire(&kn->dep_map, 0, 1, _RET_IP_); 157562306a36Sopenharmony_ci} 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci/** 157862306a36Sopenharmony_ci * kernfs_remove_self - remove a kernfs_node from its own method 157962306a36Sopenharmony_ci * @kn: the self kernfs_node to remove 158062306a36Sopenharmony_ci * 158162306a36Sopenharmony_ci * The caller must be running off of a kernfs operation which is invoked 158262306a36Sopenharmony_ci * with an active reference - e.g. one of kernfs_ops. This can be used to 158362306a36Sopenharmony_ci * implement a file operation which deletes itself. 158462306a36Sopenharmony_ci * 158562306a36Sopenharmony_ci * For example, the "delete" file for a sysfs device directory can be 158662306a36Sopenharmony_ci * implemented by invoking kernfs_remove_self() on the "delete" file 158762306a36Sopenharmony_ci * itself. This function breaks the circular dependency of trying to 158862306a36Sopenharmony_ci * deactivate self while holding an active ref itself. It isn't necessary 158962306a36Sopenharmony_ci * to modify the usual removal path to use kernfs_remove_self(). The 159062306a36Sopenharmony_ci * "delete" implementation can simply invoke kernfs_remove_self() on self 159162306a36Sopenharmony_ci * before proceeding with the usual removal path. kernfs will ignore later 159262306a36Sopenharmony_ci * kernfs_remove() on self. 159362306a36Sopenharmony_ci * 159462306a36Sopenharmony_ci * kernfs_remove_self() can be called multiple times concurrently on the 159562306a36Sopenharmony_ci * same kernfs_node. Only the first one actually performs removal and 159662306a36Sopenharmony_ci * returns %true. All others will wait until the kernfs operation which 159762306a36Sopenharmony_ci * won self-removal finishes and return %false. Note that the losers wait 159862306a36Sopenharmony_ci * for the completion of not only the winning kernfs_remove_self() but also 159962306a36Sopenharmony_ci * the whole kernfs_ops which won the arbitration. This can be used to 160062306a36Sopenharmony_ci * guarantee, for example, all concurrent writes to a "delete" file to 160162306a36Sopenharmony_ci * finish only after the whole operation is complete. 160262306a36Sopenharmony_ci * 160362306a36Sopenharmony_ci * Return: %true if @kn is removed by this call, otherwise %false. 160462306a36Sopenharmony_ci */ 160562306a36Sopenharmony_cibool kernfs_remove_self(struct kernfs_node *kn) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci bool ret; 160862306a36Sopenharmony_ci struct kernfs_root *root = kernfs_root(kn); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 161162306a36Sopenharmony_ci kernfs_break_active_protection(kn); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci /* 161462306a36Sopenharmony_ci * SUICIDAL is used to arbitrate among competing invocations. Only 161562306a36Sopenharmony_ci * the first one will actually perform removal. When the removal 161662306a36Sopenharmony_ci * is complete, SUICIDED is set and the active ref is restored 161762306a36Sopenharmony_ci * while kernfs_rwsem for held exclusive. The ones which lost 161862306a36Sopenharmony_ci * arbitration waits for SUICIDED && drained which can happen only 161962306a36Sopenharmony_ci * after the enclosing kernfs operation which executed the winning 162062306a36Sopenharmony_ci * instance of kernfs_remove_self() finished. 162162306a36Sopenharmony_ci */ 162262306a36Sopenharmony_ci if (!(kn->flags & KERNFS_SUICIDAL)) { 162362306a36Sopenharmony_ci kn->flags |= KERNFS_SUICIDAL; 162462306a36Sopenharmony_ci __kernfs_remove(kn); 162562306a36Sopenharmony_ci kn->flags |= KERNFS_SUICIDED; 162662306a36Sopenharmony_ci ret = true; 162762306a36Sopenharmony_ci } else { 162862306a36Sopenharmony_ci wait_queue_head_t *waitq = &kernfs_root(kn)->deactivate_waitq; 162962306a36Sopenharmony_ci DEFINE_WAIT(wait); 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci while (true) { 163262306a36Sopenharmony_ci prepare_to_wait(waitq, &wait, TASK_UNINTERRUPTIBLE); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci if ((kn->flags & KERNFS_SUICIDED) && 163562306a36Sopenharmony_ci atomic_read(&kn->active) == KN_DEACTIVATED_BIAS) 163662306a36Sopenharmony_ci break; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 163962306a36Sopenharmony_ci schedule(); 164062306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci finish_wait(waitq, &wait); 164362306a36Sopenharmony_ci WARN_ON_ONCE(!RB_EMPTY_NODE(&kn->rb)); 164462306a36Sopenharmony_ci ret = false; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* 164862306a36Sopenharmony_ci * This must be done while kernfs_rwsem held exclusive; otherwise, 164962306a36Sopenharmony_ci * waiting for SUICIDED && deactivated could finish prematurely. 165062306a36Sopenharmony_ci */ 165162306a36Sopenharmony_ci kernfs_unbreak_active_protection(kn); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 165462306a36Sopenharmony_ci return ret; 165562306a36Sopenharmony_ci} 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci/** 165862306a36Sopenharmony_ci * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it 165962306a36Sopenharmony_ci * @parent: parent of the target 166062306a36Sopenharmony_ci * @name: name of the kernfs_node to remove 166162306a36Sopenharmony_ci * @ns: namespace tag of the kernfs_node to remove 166262306a36Sopenharmony_ci * 166362306a36Sopenharmony_ci * Look for the kernfs_node with @name and @ns under @parent and remove it. 166462306a36Sopenharmony_ci * 166562306a36Sopenharmony_ci * Return: %0 on success, -ENOENT if such entry doesn't exist. 166662306a36Sopenharmony_ci */ 166762306a36Sopenharmony_ciint kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, 166862306a36Sopenharmony_ci const void *ns) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci struct kernfs_node *kn; 167162306a36Sopenharmony_ci struct kernfs_root *root; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (!parent) { 167462306a36Sopenharmony_ci WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n", 167562306a36Sopenharmony_ci name); 167662306a36Sopenharmony_ci return -ENOENT; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci root = kernfs_root(parent); 168062306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci kn = kernfs_find_ns(parent, name, ns); 168362306a36Sopenharmony_ci if (kn) { 168462306a36Sopenharmony_ci kernfs_get(kn); 168562306a36Sopenharmony_ci __kernfs_remove(kn); 168662306a36Sopenharmony_ci kernfs_put(kn); 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci if (kn) 169262306a36Sopenharmony_ci return 0; 169362306a36Sopenharmony_ci else 169462306a36Sopenharmony_ci return -ENOENT; 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci/** 169862306a36Sopenharmony_ci * kernfs_rename_ns - move and rename a kernfs_node 169962306a36Sopenharmony_ci * @kn: target node 170062306a36Sopenharmony_ci * @new_parent: new parent to put @sd under 170162306a36Sopenharmony_ci * @new_name: new name 170262306a36Sopenharmony_ci * @new_ns: new namespace tag 170362306a36Sopenharmony_ci * 170462306a36Sopenharmony_ci * Return: %0 on success, -errno on failure. 170562306a36Sopenharmony_ci */ 170662306a36Sopenharmony_ciint kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, 170762306a36Sopenharmony_ci const char *new_name, const void *new_ns) 170862306a36Sopenharmony_ci{ 170962306a36Sopenharmony_ci struct kernfs_node *old_parent; 171062306a36Sopenharmony_ci struct kernfs_root *root; 171162306a36Sopenharmony_ci const char *old_name = NULL; 171262306a36Sopenharmony_ci int error; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci /* can't move or rename root */ 171562306a36Sopenharmony_ci if (!kn->parent) 171662306a36Sopenharmony_ci return -EINVAL; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci root = kernfs_root(kn); 171962306a36Sopenharmony_ci down_write(&root->kernfs_rwsem); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci error = -ENOENT; 172262306a36Sopenharmony_ci if (!kernfs_active(kn) || !kernfs_active(new_parent) || 172362306a36Sopenharmony_ci (new_parent->flags & KERNFS_EMPTY_DIR)) 172462306a36Sopenharmony_ci goto out; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci error = 0; 172762306a36Sopenharmony_ci if ((kn->parent == new_parent) && (kn->ns == new_ns) && 172862306a36Sopenharmony_ci (strcmp(kn->name, new_name) == 0)) 172962306a36Sopenharmony_ci goto out; /* nothing to rename */ 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci error = -EEXIST; 173262306a36Sopenharmony_ci if (kernfs_find_ns(new_parent, new_name, new_ns)) 173362306a36Sopenharmony_ci goto out; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci /* rename kernfs_node */ 173662306a36Sopenharmony_ci if (strcmp(kn->name, new_name) != 0) { 173762306a36Sopenharmony_ci error = -ENOMEM; 173862306a36Sopenharmony_ci new_name = kstrdup_const(new_name, GFP_KERNEL); 173962306a36Sopenharmony_ci if (!new_name) 174062306a36Sopenharmony_ci goto out; 174162306a36Sopenharmony_ci } else { 174262306a36Sopenharmony_ci new_name = NULL; 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci /* 174662306a36Sopenharmony_ci * Move to the appropriate place in the appropriate directories rbtree. 174762306a36Sopenharmony_ci */ 174862306a36Sopenharmony_ci kernfs_unlink_sibling(kn); 174962306a36Sopenharmony_ci kernfs_get(new_parent); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci /* rename_lock protects ->parent and ->name accessors */ 175262306a36Sopenharmony_ci write_lock_irq(&kernfs_rename_lock); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci old_parent = kn->parent; 175562306a36Sopenharmony_ci kn->parent = new_parent; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci kn->ns = new_ns; 175862306a36Sopenharmony_ci if (new_name) { 175962306a36Sopenharmony_ci old_name = kn->name; 176062306a36Sopenharmony_ci kn->name = new_name; 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci write_unlock_irq(&kernfs_rename_lock); 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci kn->hash = kernfs_name_hash(kn->name, kn->ns); 176662306a36Sopenharmony_ci kernfs_link_sibling(kn); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci kernfs_put(old_parent); 176962306a36Sopenharmony_ci kfree_const(old_name); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci error = 0; 177262306a36Sopenharmony_ci out: 177362306a36Sopenharmony_ci up_write(&root->kernfs_rwsem); 177462306a36Sopenharmony_ci return error; 177562306a36Sopenharmony_ci} 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_cistatic int kernfs_dir_fop_release(struct inode *inode, struct file *filp) 177862306a36Sopenharmony_ci{ 177962306a36Sopenharmony_ci kernfs_put(filp->private_data); 178062306a36Sopenharmony_ci return 0; 178162306a36Sopenharmony_ci} 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_cistatic struct kernfs_node *kernfs_dir_pos(const void *ns, 178462306a36Sopenharmony_ci struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) 178562306a36Sopenharmony_ci{ 178662306a36Sopenharmony_ci if (pos) { 178762306a36Sopenharmony_ci int valid = kernfs_active(pos) && 178862306a36Sopenharmony_ci pos->parent == parent && hash == pos->hash; 178962306a36Sopenharmony_ci kernfs_put(pos); 179062306a36Sopenharmony_ci if (!valid) 179162306a36Sopenharmony_ci pos = NULL; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci if (!pos && (hash > 1) && (hash < INT_MAX)) { 179462306a36Sopenharmony_ci struct rb_node *node = parent->dir.children.rb_node; 179562306a36Sopenharmony_ci while (node) { 179662306a36Sopenharmony_ci pos = rb_to_kn(node); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci if (hash < pos->hash) 179962306a36Sopenharmony_ci node = node->rb_left; 180062306a36Sopenharmony_ci else if (hash > pos->hash) 180162306a36Sopenharmony_ci node = node->rb_right; 180262306a36Sopenharmony_ci else 180362306a36Sopenharmony_ci break; 180462306a36Sopenharmony_ci } 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci /* Skip over entries which are dying/dead or in the wrong namespace */ 180762306a36Sopenharmony_ci while (pos && (!kernfs_active(pos) || pos->ns != ns)) { 180862306a36Sopenharmony_ci struct rb_node *node = rb_next(&pos->rb); 180962306a36Sopenharmony_ci if (!node) 181062306a36Sopenharmony_ci pos = NULL; 181162306a36Sopenharmony_ci else 181262306a36Sopenharmony_ci pos = rb_to_kn(node); 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci return pos; 181562306a36Sopenharmony_ci} 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_cistatic struct kernfs_node *kernfs_dir_next_pos(const void *ns, 181862306a36Sopenharmony_ci struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos) 181962306a36Sopenharmony_ci{ 182062306a36Sopenharmony_ci pos = kernfs_dir_pos(ns, parent, ino, pos); 182162306a36Sopenharmony_ci if (pos) { 182262306a36Sopenharmony_ci do { 182362306a36Sopenharmony_ci struct rb_node *node = rb_next(&pos->rb); 182462306a36Sopenharmony_ci if (!node) 182562306a36Sopenharmony_ci pos = NULL; 182662306a36Sopenharmony_ci else 182762306a36Sopenharmony_ci pos = rb_to_kn(node); 182862306a36Sopenharmony_ci } while (pos && (!kernfs_active(pos) || pos->ns != ns)); 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci return pos; 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_cistatic int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci struct dentry *dentry = file->f_path.dentry; 183662306a36Sopenharmony_ci struct kernfs_node *parent = kernfs_dentry_node(dentry); 183762306a36Sopenharmony_ci struct kernfs_node *pos = file->private_data; 183862306a36Sopenharmony_ci struct kernfs_root *root; 183962306a36Sopenharmony_ci const void *ns = NULL; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci if (!dir_emit_dots(file, ctx)) 184262306a36Sopenharmony_ci return 0; 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci root = kernfs_root(parent); 184562306a36Sopenharmony_ci down_read(&root->kernfs_rwsem); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci if (kernfs_ns_enabled(parent)) 184862306a36Sopenharmony_ci ns = kernfs_info(dentry->d_sb)->ns; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos); 185162306a36Sopenharmony_ci pos; 185262306a36Sopenharmony_ci pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) { 185362306a36Sopenharmony_ci const char *name = pos->name; 185462306a36Sopenharmony_ci unsigned int type = fs_umode_to_dtype(pos->mode); 185562306a36Sopenharmony_ci int len = strlen(name); 185662306a36Sopenharmony_ci ino_t ino = kernfs_ino(pos); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci ctx->pos = pos->hash; 185962306a36Sopenharmony_ci file->private_data = pos; 186062306a36Sopenharmony_ci kernfs_get(pos); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 186362306a36Sopenharmony_ci if (!dir_emit(ctx, name, len, ino, type)) 186462306a36Sopenharmony_ci return 0; 186562306a36Sopenharmony_ci down_read(&root->kernfs_rwsem); 186662306a36Sopenharmony_ci } 186762306a36Sopenharmony_ci up_read(&root->kernfs_rwsem); 186862306a36Sopenharmony_ci file->private_data = NULL; 186962306a36Sopenharmony_ci ctx->pos = INT_MAX; 187062306a36Sopenharmony_ci return 0; 187162306a36Sopenharmony_ci} 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ciconst struct file_operations kernfs_dir_fops = { 187462306a36Sopenharmony_ci .read = generic_read_dir, 187562306a36Sopenharmony_ci .iterate_shared = kernfs_fop_readdir, 187662306a36Sopenharmony_ci .release = kernfs_dir_fop_release, 187762306a36Sopenharmony_ci .llseek = generic_file_llseek, 187862306a36Sopenharmony_ci}; 1879