1b8441ed2STejun Heo /* 2b8441ed2STejun Heo * fs/kernfs/dir.c - kernfs directory implementation 3b8441ed2STejun Heo * 4b8441ed2STejun Heo * Copyright (c) 2001-3 Patrick Mochel 5b8441ed2STejun Heo * Copyright (c) 2007 SUSE Linux Products GmbH 6b8441ed2STejun Heo * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org> 7b8441ed2STejun Heo * 8b8441ed2STejun Heo * This file is released under the GPLv2. 9b8441ed2STejun Heo */ 10fd7b9f7bSTejun Heo 11abd54f02STejun Heo #include <linux/sched.h> 12fd7b9f7bSTejun Heo #include <linux/fs.h> 13fd7b9f7bSTejun Heo #include <linux/namei.h> 14fd7b9f7bSTejun Heo #include <linux/idr.h> 15fd7b9f7bSTejun Heo #include <linux/slab.h> 16fd7b9f7bSTejun Heo #include <linux/security.h> 17fd7b9f7bSTejun Heo #include <linux/hash.h> 18fd7b9f7bSTejun Heo 19fd7b9f7bSTejun Heo #include "kernfs-internal.h" 20fd7b9f7bSTejun Heo 21a797bfc3STejun Heo DEFINE_MUTEX(kernfs_mutex); 22fd7b9f7bSTejun Heo 23adc5e8b5STejun Heo #define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb) 24fd7b9f7bSTejun Heo 25fd7b9f7bSTejun Heo /** 26c637b8acSTejun Heo * kernfs_name_hash 27fd7b9f7bSTejun Heo * @name: Null terminated string to hash 28fd7b9f7bSTejun Heo * @ns: Namespace tag to hash 29fd7b9f7bSTejun Heo * 30fd7b9f7bSTejun Heo * Returns 31 bit hash of ns + name (so it fits in an off_t ) 31fd7b9f7bSTejun Heo */ 32c637b8acSTejun Heo static unsigned int kernfs_name_hash(const char *name, const void *ns) 33fd7b9f7bSTejun Heo { 34fd7b9f7bSTejun Heo unsigned long hash = init_name_hash(); 35fd7b9f7bSTejun Heo unsigned int len = strlen(name); 36fd7b9f7bSTejun Heo while (len--) 37fd7b9f7bSTejun Heo hash = partial_name_hash(*name++, hash); 38fd7b9f7bSTejun Heo hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31)); 39fd7b9f7bSTejun Heo hash &= 0x7fffffffU; 40fd7b9f7bSTejun Heo /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ 41fd7b9f7bSTejun Heo if (hash < 1) 42fd7b9f7bSTejun Heo hash += 2; 43fd7b9f7bSTejun Heo if (hash >= INT_MAX) 44fd7b9f7bSTejun Heo hash = INT_MAX - 1; 45fd7b9f7bSTejun Heo return hash; 46fd7b9f7bSTejun Heo } 47fd7b9f7bSTejun Heo 48c637b8acSTejun Heo static int kernfs_name_compare(unsigned int hash, const char *name, 49324a56e1STejun Heo const void *ns, const struct kernfs_node *kn) 50fd7b9f7bSTejun Heo { 51adc5e8b5STejun Heo if (hash != kn->hash) 52adc5e8b5STejun Heo return hash - kn->hash; 53adc5e8b5STejun Heo if (ns != kn->ns) 54adc5e8b5STejun Heo return ns - kn->ns; 55adc5e8b5STejun Heo return strcmp(name, kn->name); 56fd7b9f7bSTejun Heo } 57fd7b9f7bSTejun Heo 58c637b8acSTejun Heo static int kernfs_sd_compare(const struct kernfs_node *left, 59324a56e1STejun Heo const struct kernfs_node *right) 60fd7b9f7bSTejun Heo { 61c637b8acSTejun Heo return kernfs_name_compare(left->hash, left->name, left->ns, right); 62fd7b9f7bSTejun Heo } 63fd7b9f7bSTejun Heo 64fd7b9f7bSTejun Heo /** 65c637b8acSTejun Heo * kernfs_link_sibling - link kernfs_node into sibling rbtree 66324a56e1STejun Heo * @kn: kernfs_node of interest 67fd7b9f7bSTejun Heo * 68324a56e1STejun Heo * Link @kn into its sibling rbtree which starts from 69adc5e8b5STejun Heo * @kn->parent->dir.children. 70fd7b9f7bSTejun Heo * 71fd7b9f7bSTejun Heo * Locking: 72a797bfc3STejun Heo * mutex_lock(kernfs_mutex) 73fd7b9f7bSTejun Heo * 74fd7b9f7bSTejun Heo * RETURNS: 75fd7b9f7bSTejun Heo * 0 on susccess -EEXIST on failure. 76fd7b9f7bSTejun Heo */ 77c637b8acSTejun Heo static int kernfs_link_sibling(struct kernfs_node *kn) 78fd7b9f7bSTejun Heo { 79adc5e8b5STejun Heo struct rb_node **node = &kn->parent->dir.children.rb_node; 80fd7b9f7bSTejun Heo struct rb_node *parent = NULL; 81fd7b9f7bSTejun Heo 82df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_DIR) 83adc5e8b5STejun Heo kn->parent->dir.subdirs++; 84fd7b9f7bSTejun Heo 85fd7b9f7bSTejun Heo while (*node) { 86324a56e1STejun Heo struct kernfs_node *pos; 87fd7b9f7bSTejun Heo int result; 88fd7b9f7bSTejun Heo 89324a56e1STejun Heo pos = rb_to_kn(*node); 90fd7b9f7bSTejun Heo parent = *node; 91c637b8acSTejun Heo result = kernfs_sd_compare(kn, pos); 92fd7b9f7bSTejun Heo if (result < 0) 93adc5e8b5STejun Heo node = &pos->rb.rb_left; 94fd7b9f7bSTejun Heo else if (result > 0) 95adc5e8b5STejun Heo node = &pos->rb.rb_right; 96fd7b9f7bSTejun Heo else 97fd7b9f7bSTejun Heo return -EEXIST; 98fd7b9f7bSTejun Heo } 99fd7b9f7bSTejun Heo /* add new node and rebalance the tree */ 100adc5e8b5STejun Heo rb_link_node(&kn->rb, parent, node); 101adc5e8b5STejun Heo rb_insert_color(&kn->rb, &kn->parent->dir.children); 102fd7b9f7bSTejun Heo return 0; 103fd7b9f7bSTejun Heo } 104fd7b9f7bSTejun Heo 105fd7b9f7bSTejun Heo /** 106c637b8acSTejun Heo * kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree 107324a56e1STejun Heo * @kn: kernfs_node of interest 108fd7b9f7bSTejun Heo * 10935beab06STejun Heo * Try to unlink @kn from its sibling rbtree which starts from 11035beab06STejun Heo * kn->parent->dir.children. Returns %true if @kn was actually 11135beab06STejun Heo * removed, %false if @kn wasn't on the rbtree. 112fd7b9f7bSTejun Heo * 113fd7b9f7bSTejun Heo * Locking: 114a797bfc3STejun Heo * mutex_lock(kernfs_mutex) 115fd7b9f7bSTejun Heo */ 11635beab06STejun Heo static bool kernfs_unlink_sibling(struct kernfs_node *kn) 117fd7b9f7bSTejun Heo { 11835beab06STejun Heo if (RB_EMPTY_NODE(&kn->rb)) 11935beab06STejun Heo return false; 12035beab06STejun Heo 121df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_DIR) 122adc5e8b5STejun Heo kn->parent->dir.subdirs--; 123fd7b9f7bSTejun Heo 124adc5e8b5STejun Heo rb_erase(&kn->rb, &kn->parent->dir.children); 12535beab06STejun Heo RB_CLEAR_NODE(&kn->rb); 12635beab06STejun Heo return true; 127fd7b9f7bSTejun Heo } 128fd7b9f7bSTejun Heo 129fd7b9f7bSTejun Heo /** 130c637b8acSTejun Heo * kernfs_get_active - get an active reference to kernfs_node 131324a56e1STejun Heo * @kn: kernfs_node to get an active reference to 132fd7b9f7bSTejun Heo * 133324a56e1STejun Heo * Get an active reference of @kn. This function is noop if @kn 134fd7b9f7bSTejun Heo * is NULL. 135fd7b9f7bSTejun Heo * 136fd7b9f7bSTejun Heo * RETURNS: 137324a56e1STejun Heo * Pointer to @kn on success, NULL on failure. 138fd7b9f7bSTejun Heo */ 139c637b8acSTejun Heo struct kernfs_node *kernfs_get_active(struct kernfs_node *kn) 140fd7b9f7bSTejun Heo { 141324a56e1STejun Heo if (unlikely(!kn)) 142fd7b9f7bSTejun Heo return NULL; 143fd7b9f7bSTejun Heo 144f4b3e631SGreg Kroah-Hartman if (!atomic_inc_unless_negative(&kn->active)) 145f4b3e631SGreg Kroah-Hartman return NULL; 146f4b3e631SGreg Kroah-Hartman 1470890147fSGreg Kroah-Hartman if (kn->flags & KERNFS_LOCKDEP) 148324a56e1STejun Heo rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); 149324a56e1STejun Heo return kn; 150fd7b9f7bSTejun Heo } 151fd7b9f7bSTejun Heo 152fd7b9f7bSTejun Heo /** 153c637b8acSTejun Heo * kernfs_put_active - put an active reference to kernfs_node 154324a56e1STejun Heo * @kn: kernfs_node to put an active reference to 155fd7b9f7bSTejun Heo * 156324a56e1STejun Heo * Put an active reference to @kn. This function is noop if @kn 157fd7b9f7bSTejun Heo * is NULL. 158fd7b9f7bSTejun Heo */ 159c637b8acSTejun Heo void kernfs_put_active(struct kernfs_node *kn) 160fd7b9f7bSTejun Heo { 161abd54f02STejun Heo struct kernfs_root *root = kernfs_root(kn); 162fd7b9f7bSTejun Heo int v; 163fd7b9f7bSTejun Heo 164324a56e1STejun Heo if (unlikely(!kn)) 165fd7b9f7bSTejun Heo return; 166fd7b9f7bSTejun Heo 1670890147fSGreg Kroah-Hartman if (kn->flags & KERNFS_LOCKDEP) 168324a56e1STejun Heo rwsem_release(&kn->dep_map, 1, _RET_IP_); 169adc5e8b5STejun Heo v = atomic_dec_return(&kn->active); 170df23fc39STejun Heo if (likely(v != KN_DEACTIVATED_BIAS)) 171fd7b9f7bSTejun Heo return; 172fd7b9f7bSTejun Heo 173abd54f02STejun Heo wake_up_all(&root->deactivate_waitq); 174fd7b9f7bSTejun Heo } 175fd7b9f7bSTejun Heo 176fd7b9f7bSTejun Heo /** 177798c75a0SGreg Kroah-Hartman * kernfs_deactivate - deactivate kernfs_node 178798c75a0SGreg Kroah-Hartman * @kn: kernfs_node to deactivate 179fd7b9f7bSTejun Heo * 180ccf02aafSTejun Heo * Deny new active references, drain existing ones and nuke all 181ccf02aafSTejun Heo * existing mmaps. Mutiple removers may invoke this function 182ccf02aafSTejun Heo * concurrently on @kn and all will return after deactivation and 183ccf02aafSTejun Heo * draining are complete. 184fd7b9f7bSTejun Heo */ 185798c75a0SGreg Kroah-Hartman static void kernfs_deactivate(struct kernfs_node *kn) 18635beab06STejun Heo __releases(&kernfs_mutex) __acquires(&kernfs_mutex) 187fd7b9f7bSTejun Heo { 188abd54f02STejun Heo struct kernfs_root *root = kernfs_root(kn); 189fd7b9f7bSTejun Heo 19035beab06STejun Heo lockdep_assert_held(&kernfs_mutex); 191798c75a0SGreg Kroah-Hartman BUG_ON(!(kn->flags & KERNFS_REMOVED)); 192798c75a0SGreg Kroah-Hartman 1930890147fSGreg Kroah-Hartman if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF)) 1940890147fSGreg Kroah-Hartman return; 1950890147fSGreg Kroah-Hartman 19635beab06STejun Heo /* only the first invocation on @kn should deactivate it */ 19735beab06STejun Heo if (atomic_read(&kn->active) >= 0) 198abd54f02STejun Heo atomic_add(KN_DEACTIVATED_BIAS, &kn->active); 199abd54f02STejun Heo 20035beab06STejun Heo mutex_unlock(&kernfs_mutex); 201abd54f02STejun Heo 20235beab06STejun Heo if (kn->flags & KERNFS_LOCKDEP) { 20335beab06STejun Heo rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); 20435beab06STejun Heo if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) 20535beab06STejun Heo lock_contended(&kn->dep_map, _RET_IP_); 20635beab06STejun Heo } 20735beab06STejun Heo 20835beab06STejun Heo /* but everyone should wait for draining */ 209abd54f02STejun Heo wait_event(root->deactivate_waitq, 210abd54f02STejun Heo atomic_read(&kn->active) == KN_DEACTIVATED_BIAS); 211fd7b9f7bSTejun Heo 212a6607930STejun Heo if (kn->flags & KERNFS_LOCKDEP) { 213324a56e1STejun Heo lock_acquired(&kn->dep_map, _RET_IP_); 214324a56e1STejun Heo rwsem_release(&kn->dep_map, 1, _RET_IP_); 215fd7b9f7bSTejun Heo } 21635beab06STejun Heo 217ccf02aafSTejun Heo kernfs_unmap_bin_file(kn); 218ccf02aafSTejun Heo 21935beab06STejun Heo mutex_lock(&kernfs_mutex); 220a6607930STejun Heo } 221fd7b9f7bSTejun Heo 222fd7b9f7bSTejun Heo /** 223324a56e1STejun Heo * kernfs_get - get a reference count on a kernfs_node 224324a56e1STejun Heo * @kn: the target kernfs_node 225fd7b9f7bSTejun Heo */ 226324a56e1STejun Heo void kernfs_get(struct kernfs_node *kn) 227fd7b9f7bSTejun Heo { 228324a56e1STejun Heo if (kn) { 229adc5e8b5STejun Heo WARN_ON(!atomic_read(&kn->count)); 230adc5e8b5STejun Heo atomic_inc(&kn->count); 231fd7b9f7bSTejun Heo } 232fd7b9f7bSTejun Heo } 233fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_get); 234fd7b9f7bSTejun Heo 235fd7b9f7bSTejun Heo /** 236324a56e1STejun Heo * kernfs_put - put a reference count on a kernfs_node 237324a56e1STejun Heo * @kn: the target kernfs_node 238fd7b9f7bSTejun Heo * 239324a56e1STejun Heo * Put a reference count of @kn and destroy it if it reached zero. 240fd7b9f7bSTejun Heo */ 241324a56e1STejun Heo void kernfs_put(struct kernfs_node *kn) 242fd7b9f7bSTejun Heo { 243324a56e1STejun Heo struct kernfs_node *parent; 244ba7443bcSTejun Heo struct kernfs_root *root; 245fd7b9f7bSTejun Heo 246adc5e8b5STejun Heo if (!kn || !atomic_dec_and_test(&kn->count)) 247fd7b9f7bSTejun Heo return; 248324a56e1STejun Heo root = kernfs_root(kn); 249fd7b9f7bSTejun Heo repeat: 250798c75a0SGreg Kroah-Hartman /* Moving/renaming is always done while holding reference. 251adc5e8b5STejun Heo * kn->parent won't change beneath us. 252fd7b9f7bSTejun Heo */ 253adc5e8b5STejun Heo parent = kn->parent; 254fd7b9f7bSTejun Heo 255798c75a0SGreg Kroah-Hartman WARN(!(kn->flags & KERNFS_REMOVED), "kernfs: free using entry: %s/%s\n", 256798c75a0SGreg Kroah-Hartman parent ? parent->name : "", kn->name); 257fd7b9f7bSTejun Heo 258df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_LINK) 259adc5e8b5STejun Heo kernfs_put(kn->symlink.target_kn); 2602063d608STejun Heo if (!(kn->flags & KERNFS_STATIC_NAME)) 261adc5e8b5STejun Heo kfree(kn->name); 262adc5e8b5STejun Heo if (kn->iattr) { 263adc5e8b5STejun Heo if (kn->iattr->ia_secdata) 264adc5e8b5STejun Heo security_release_secctx(kn->iattr->ia_secdata, 265adc5e8b5STejun Heo kn->iattr->ia_secdata_len); 266adc5e8b5STejun Heo simple_xattrs_free(&kn->iattr->xattrs); 2672322392bSTejun Heo } 268adc5e8b5STejun Heo kfree(kn->iattr); 269adc5e8b5STejun Heo ida_simple_remove(&root->ino_ida, kn->ino); 270a797bfc3STejun Heo kmem_cache_free(kernfs_node_cache, kn); 271fd7b9f7bSTejun Heo 272324a56e1STejun Heo kn = parent; 273324a56e1STejun Heo if (kn) { 274adc5e8b5STejun Heo if (atomic_dec_and_test(&kn->count)) 275fd7b9f7bSTejun Heo goto repeat; 276ba7443bcSTejun Heo } else { 277324a56e1STejun Heo /* just released the root kn, free @root too */ 278bc755553STejun Heo ida_destroy(&root->ino_ida); 279ba7443bcSTejun Heo kfree(root); 280ba7443bcSTejun Heo } 281fd7b9f7bSTejun Heo } 282fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_put); 283fd7b9f7bSTejun Heo 284c637b8acSTejun Heo static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) 285fd7b9f7bSTejun Heo { 286324a56e1STejun Heo struct kernfs_node *kn; 287fd7b9f7bSTejun Heo 288fd7b9f7bSTejun Heo if (flags & LOOKUP_RCU) 289fd7b9f7bSTejun Heo return -ECHILD; 290fd7b9f7bSTejun Heo 29119bbb926STejun Heo /* Always perform fresh lookup for negatives */ 29219bbb926STejun Heo if (!dentry->d_inode) 29319bbb926STejun Heo goto out_bad_unlocked; 29419bbb926STejun Heo 295324a56e1STejun Heo kn = dentry->d_fsdata; 296a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 297fd7b9f7bSTejun Heo 298798c75a0SGreg Kroah-Hartman /* The kernfs node has been deleted */ 299798c75a0SGreg Kroah-Hartman if (kn->flags & KERNFS_REMOVED) 300fd7b9f7bSTejun Heo goto out_bad; 301fd7b9f7bSTejun Heo 302c637b8acSTejun Heo /* The kernfs node has been moved? */ 303adc5e8b5STejun Heo if (dentry->d_parent->d_fsdata != kn->parent) 304fd7b9f7bSTejun Heo goto out_bad; 305fd7b9f7bSTejun Heo 306c637b8acSTejun Heo /* The kernfs node has been renamed */ 307adc5e8b5STejun Heo if (strcmp(dentry->d_name.name, kn->name) != 0) 308fd7b9f7bSTejun Heo goto out_bad; 309fd7b9f7bSTejun Heo 310c637b8acSTejun Heo /* The kernfs node has been moved to a different namespace */ 311adc5e8b5STejun Heo if (kn->parent && kernfs_ns_enabled(kn->parent) && 312c525aaddSTejun Heo kernfs_info(dentry->d_sb)->ns != kn->ns) 313fd7b9f7bSTejun Heo goto out_bad; 314fd7b9f7bSTejun Heo 315a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 316fd7b9f7bSTejun Heo out_valid: 317fd7b9f7bSTejun Heo return 1; 318fd7b9f7bSTejun Heo out_bad: 319a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 32019bbb926STejun Heo out_bad_unlocked: 32119bbb926STejun Heo /* 32219bbb926STejun Heo * @dentry doesn't match the underlying kernfs node, drop the 32319bbb926STejun Heo * dentry and force lookup. If we have submounts we must allow the 32419bbb926STejun Heo * vfs caches to lie about the state of the filesystem to prevent 32519bbb926STejun Heo * leaks and other nasty things, so use check_submounts_and_drop() 32619bbb926STejun Heo * instead of d_drop(). 327fd7b9f7bSTejun Heo */ 328fd7b9f7bSTejun Heo if (check_submounts_and_drop(dentry) != 0) 329fd7b9f7bSTejun Heo goto out_valid; 330fd7b9f7bSTejun Heo 331fd7b9f7bSTejun Heo return 0; 332fd7b9f7bSTejun Heo } 333fd7b9f7bSTejun Heo 334c637b8acSTejun Heo static void kernfs_dop_release(struct dentry *dentry) 335fd7b9f7bSTejun Heo { 336fd7b9f7bSTejun Heo kernfs_put(dentry->d_fsdata); 337fd7b9f7bSTejun Heo } 338fd7b9f7bSTejun Heo 339a797bfc3STejun Heo const struct dentry_operations kernfs_dops = { 340c637b8acSTejun Heo .d_revalidate = kernfs_dop_revalidate, 341c637b8acSTejun Heo .d_release = kernfs_dop_release, 342fd7b9f7bSTejun Heo }; 343fd7b9f7bSTejun Heo 344db4aad20STejun Heo static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, 345db4aad20STejun Heo const char *name, umode_t mode, 346db4aad20STejun Heo unsigned flags) 347fd7b9f7bSTejun Heo { 348fd7b9f7bSTejun Heo char *dup_name = NULL; 349324a56e1STejun Heo struct kernfs_node *kn; 350bc755553STejun Heo int ret; 351fd7b9f7bSTejun Heo 3522063d608STejun Heo if (!(flags & KERNFS_STATIC_NAME)) { 353fd7b9f7bSTejun Heo name = dup_name = kstrdup(name, GFP_KERNEL); 354fd7b9f7bSTejun Heo if (!name) 355fd7b9f7bSTejun Heo return NULL; 356fd7b9f7bSTejun Heo } 357fd7b9f7bSTejun Heo 358a797bfc3STejun Heo kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL); 359324a56e1STejun Heo if (!kn) 360fd7b9f7bSTejun Heo goto err_out1; 361fd7b9f7bSTejun Heo 362bc755553STejun Heo ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL); 363bc755553STejun Heo if (ret < 0) 364fd7b9f7bSTejun Heo goto err_out2; 365adc5e8b5STejun Heo kn->ino = ret; 366fd7b9f7bSTejun Heo 367adc5e8b5STejun Heo atomic_set(&kn->count, 1); 368798c75a0SGreg Kroah-Hartman atomic_set(&kn->active, 0); 36935beab06STejun Heo RB_CLEAR_NODE(&kn->rb); 370fd7b9f7bSTejun Heo 371adc5e8b5STejun Heo kn->name = name; 372adc5e8b5STejun Heo kn->mode = mode; 373798c75a0SGreg Kroah-Hartman kn->flags = flags | KERNFS_REMOVED; 374fd7b9f7bSTejun Heo 375324a56e1STejun Heo return kn; 376fd7b9f7bSTejun Heo 377fd7b9f7bSTejun Heo err_out2: 378a797bfc3STejun Heo kmem_cache_free(kernfs_node_cache, kn); 379fd7b9f7bSTejun Heo err_out1: 380fd7b9f7bSTejun Heo kfree(dup_name); 381fd7b9f7bSTejun Heo return NULL; 382fd7b9f7bSTejun Heo } 383fd7b9f7bSTejun Heo 384db4aad20STejun Heo struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, 385db4aad20STejun Heo const char *name, umode_t mode, 386db4aad20STejun Heo unsigned flags) 387db4aad20STejun Heo { 388db4aad20STejun Heo struct kernfs_node *kn; 389db4aad20STejun Heo 390db4aad20STejun Heo kn = __kernfs_new_node(kernfs_root(parent), name, mode, flags); 391db4aad20STejun Heo if (kn) { 392db4aad20STejun Heo kernfs_get(parent); 393db4aad20STejun Heo kn->parent = parent; 394db4aad20STejun Heo } 395db4aad20STejun Heo return kn; 396db4aad20STejun Heo } 397db4aad20STejun Heo 398fd7b9f7bSTejun Heo /** 399c637b8acSTejun Heo * kernfs_add_one - add kernfs_node to parent without warning 400324a56e1STejun Heo * @kn: kernfs_node to be added 401fd7b9f7bSTejun Heo * 402db4aad20STejun Heo * The caller must already have initialized @kn->parent. This 403db4aad20STejun Heo * function increments nlink of the parent's inode if @kn is a 404db4aad20STejun Heo * directory and link into the children list of the parent. 405fd7b9f7bSTejun Heo * 406fd7b9f7bSTejun Heo * RETURNS: 407fd7b9f7bSTejun Heo * 0 on success, -EEXIST if entry with the given name already 408fd7b9f7bSTejun Heo * exists. 409fd7b9f7bSTejun Heo */ 410988cd7afSTejun Heo int kernfs_add_one(struct kernfs_node *kn) 411fd7b9f7bSTejun Heo { 412db4aad20STejun Heo struct kernfs_node *parent = kn->parent; 413c525aaddSTejun Heo struct kernfs_iattrs *ps_iattr; 414988cd7afSTejun Heo bool has_ns; 415fd7b9f7bSTejun Heo int ret; 416fd7b9f7bSTejun Heo 417988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 418988cd7afSTejun Heo 419988cd7afSTejun Heo ret = -EINVAL; 420988cd7afSTejun Heo has_ns = kernfs_ns_enabled(parent); 421988cd7afSTejun Heo if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 422988cd7afSTejun Heo has_ns ? "required" : "invalid", parent->name, kn->name)) 423988cd7afSTejun Heo goto out_unlock; 424fd7b9f7bSTejun Heo 425df23fc39STejun Heo if (kernfs_type(parent) != KERNFS_DIR) 426988cd7afSTejun Heo goto out_unlock; 427fd7b9f7bSTejun Heo 428988cd7afSTejun Heo ret = -ENOENT; 429798c75a0SGreg Kroah-Hartman if (parent->flags & KERNFS_REMOVED) 430988cd7afSTejun Heo goto out_unlock; 431798c75a0SGreg Kroah-Hartman 432c637b8acSTejun Heo kn->hash = kernfs_name_hash(kn->name, kn->ns); 433fd7b9f7bSTejun Heo 434c637b8acSTejun Heo ret = kernfs_link_sibling(kn); 435fd7b9f7bSTejun Heo if (ret) 436988cd7afSTejun Heo goto out_unlock; 437fd7b9f7bSTejun Heo 438fd7b9f7bSTejun Heo /* Update timestamps on the parent */ 439adc5e8b5STejun Heo ps_iattr = parent->iattr; 440fd7b9f7bSTejun Heo if (ps_iattr) { 441fd7b9f7bSTejun Heo struct iattr *ps_iattrs = &ps_iattr->ia_iattr; 442fd7b9f7bSTejun Heo ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; 443fd7b9f7bSTejun Heo } 444fd7b9f7bSTejun Heo 445fd7b9f7bSTejun Heo /* Mark the entry added into directory tree */ 446798c75a0SGreg Kroah-Hartman kn->flags &= ~KERNFS_REMOVED; 447988cd7afSTejun Heo ret = 0; 448988cd7afSTejun Heo out_unlock: 449a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 450988cd7afSTejun Heo return ret; 451fd7b9f7bSTejun Heo } 452fd7b9f7bSTejun Heo 453fd7b9f7bSTejun Heo /** 454324a56e1STejun Heo * kernfs_find_ns - find kernfs_node with the given name 455324a56e1STejun Heo * @parent: kernfs_node to search under 456fd7b9f7bSTejun Heo * @name: name to look for 457fd7b9f7bSTejun Heo * @ns: the namespace tag to use 458fd7b9f7bSTejun Heo * 459324a56e1STejun Heo * Look for kernfs_node with name @name under @parent. Returns pointer to 460324a56e1STejun Heo * the found kernfs_node on success, %NULL on failure. 461fd7b9f7bSTejun Heo */ 462324a56e1STejun Heo static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, 463fd7b9f7bSTejun Heo const unsigned char *name, 464fd7b9f7bSTejun Heo const void *ns) 465fd7b9f7bSTejun Heo { 466adc5e8b5STejun Heo struct rb_node *node = parent->dir.children.rb_node; 467ac9bba03STejun Heo bool has_ns = kernfs_ns_enabled(parent); 468fd7b9f7bSTejun Heo unsigned int hash; 469fd7b9f7bSTejun Heo 470a797bfc3STejun Heo lockdep_assert_held(&kernfs_mutex); 471fd7b9f7bSTejun Heo 472fd7b9f7bSTejun Heo if (has_ns != (bool)ns) { 473c637b8acSTejun Heo WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 474adc5e8b5STejun Heo has_ns ? "required" : "invalid", parent->name, name); 475fd7b9f7bSTejun Heo return NULL; 476fd7b9f7bSTejun Heo } 477fd7b9f7bSTejun Heo 478c637b8acSTejun Heo hash = kernfs_name_hash(name, ns); 479fd7b9f7bSTejun Heo while (node) { 480324a56e1STejun Heo struct kernfs_node *kn; 481fd7b9f7bSTejun Heo int result; 482fd7b9f7bSTejun Heo 483324a56e1STejun Heo kn = rb_to_kn(node); 484c637b8acSTejun Heo result = kernfs_name_compare(hash, name, ns, kn); 485fd7b9f7bSTejun Heo if (result < 0) 486fd7b9f7bSTejun Heo node = node->rb_left; 487fd7b9f7bSTejun Heo else if (result > 0) 488fd7b9f7bSTejun Heo node = node->rb_right; 489fd7b9f7bSTejun Heo else 490324a56e1STejun Heo return kn; 491fd7b9f7bSTejun Heo } 492fd7b9f7bSTejun Heo return NULL; 493fd7b9f7bSTejun Heo } 494fd7b9f7bSTejun Heo 495fd7b9f7bSTejun Heo /** 496324a56e1STejun Heo * kernfs_find_and_get_ns - find and get kernfs_node with the given name 497324a56e1STejun Heo * @parent: kernfs_node to search under 498fd7b9f7bSTejun Heo * @name: name to look for 499fd7b9f7bSTejun Heo * @ns: the namespace tag to use 500fd7b9f7bSTejun Heo * 501324a56e1STejun Heo * Look for kernfs_node with name @name under @parent and get a reference 502fd7b9f7bSTejun Heo * if found. This function may sleep and returns pointer to the found 503324a56e1STejun Heo * kernfs_node on success, %NULL on failure. 504fd7b9f7bSTejun Heo */ 505324a56e1STejun Heo struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, 506fd7b9f7bSTejun Heo const char *name, const void *ns) 507fd7b9f7bSTejun Heo { 508324a56e1STejun Heo struct kernfs_node *kn; 509fd7b9f7bSTejun Heo 510a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 511324a56e1STejun Heo kn = kernfs_find_ns(parent, name, ns); 512324a56e1STejun Heo kernfs_get(kn); 513a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 514fd7b9f7bSTejun Heo 515324a56e1STejun Heo return kn; 516fd7b9f7bSTejun Heo } 517fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); 518fd7b9f7bSTejun Heo 519fd7b9f7bSTejun Heo /** 520ba7443bcSTejun Heo * kernfs_create_root - create a new kernfs hierarchy 52180b9bbefSTejun Heo * @kdops: optional directory syscall operations for the hierarchy 522ba7443bcSTejun Heo * @priv: opaque data associated with the new directory 523ba7443bcSTejun Heo * 524ba7443bcSTejun Heo * Returns the root of the new hierarchy on success, ERR_PTR() value on 525ba7443bcSTejun Heo * failure. 526ba7443bcSTejun Heo */ 52780b9bbefSTejun Heo struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv) 528ba7443bcSTejun Heo { 529ba7443bcSTejun Heo struct kernfs_root *root; 530324a56e1STejun Heo struct kernfs_node *kn; 531ba7443bcSTejun Heo 532ba7443bcSTejun Heo root = kzalloc(sizeof(*root), GFP_KERNEL); 533ba7443bcSTejun Heo if (!root) 534ba7443bcSTejun Heo return ERR_PTR(-ENOMEM); 535ba7443bcSTejun Heo 536bc755553STejun Heo ida_init(&root->ino_ida); 537bc755553STejun Heo 538db4aad20STejun Heo kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, 539db4aad20STejun Heo KERNFS_DIR); 540324a56e1STejun Heo if (!kn) { 541bc755553STejun Heo ida_destroy(&root->ino_ida); 542ba7443bcSTejun Heo kfree(root); 543ba7443bcSTejun Heo return ERR_PTR(-ENOMEM); 544ba7443bcSTejun Heo } 545ba7443bcSTejun Heo 546798c75a0SGreg Kroah-Hartman kn->flags &= ~KERNFS_REMOVED; 547324a56e1STejun Heo kn->priv = priv; 548adc5e8b5STejun Heo kn->dir.root = root; 549ba7443bcSTejun Heo 55080b9bbefSTejun Heo root->dir_ops = kdops; 551324a56e1STejun Heo root->kn = kn; 552abd54f02STejun Heo init_waitqueue_head(&root->deactivate_waitq); 553ba7443bcSTejun Heo 554ba7443bcSTejun Heo return root; 555ba7443bcSTejun Heo } 556ba7443bcSTejun Heo 557ba7443bcSTejun Heo /** 558ba7443bcSTejun Heo * kernfs_destroy_root - destroy a kernfs hierarchy 559ba7443bcSTejun Heo * @root: root of the hierarchy to destroy 560ba7443bcSTejun Heo * 561ba7443bcSTejun Heo * Destroy the hierarchy anchored at @root by removing all existing 562ba7443bcSTejun Heo * directories and destroying @root. 563ba7443bcSTejun Heo */ 564ba7443bcSTejun Heo void kernfs_destroy_root(struct kernfs_root *root) 565ba7443bcSTejun Heo { 566324a56e1STejun Heo kernfs_remove(root->kn); /* will also free @root */ 567ba7443bcSTejun Heo } 568ba7443bcSTejun Heo 569ba7443bcSTejun Heo /** 570fd7b9f7bSTejun Heo * kernfs_create_dir_ns - create a directory 571fd7b9f7bSTejun Heo * @parent: parent in which to create a new directory 572fd7b9f7bSTejun Heo * @name: name of the new directory 573bb8b9d09STejun Heo * @mode: mode of the new directory 574fd7b9f7bSTejun Heo * @priv: opaque data associated with the new directory 575fd7b9f7bSTejun Heo * @ns: optional namespace tag of the directory 576fd7b9f7bSTejun Heo * 577fd7b9f7bSTejun Heo * Returns the created node on success, ERR_PTR() value on failure. 578fd7b9f7bSTejun Heo */ 579324a56e1STejun Heo struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, 580bb8b9d09STejun Heo const char *name, umode_t mode, 581bb8b9d09STejun Heo void *priv, const void *ns) 582fd7b9f7bSTejun Heo { 583324a56e1STejun Heo struct kernfs_node *kn; 584fd7b9f7bSTejun Heo int rc; 585fd7b9f7bSTejun Heo 586fd7b9f7bSTejun Heo /* allocate */ 587db4aad20STejun Heo kn = kernfs_new_node(parent, name, mode | S_IFDIR, KERNFS_DIR); 588324a56e1STejun Heo if (!kn) 589fd7b9f7bSTejun Heo return ERR_PTR(-ENOMEM); 590fd7b9f7bSTejun Heo 591adc5e8b5STejun Heo kn->dir.root = parent->dir.root; 592adc5e8b5STejun Heo kn->ns = ns; 593324a56e1STejun Heo kn->priv = priv; 594fd7b9f7bSTejun Heo 595fd7b9f7bSTejun Heo /* link in */ 596988cd7afSTejun Heo rc = kernfs_add_one(kn); 597fd7b9f7bSTejun Heo if (!rc) 598324a56e1STejun Heo return kn; 599fd7b9f7bSTejun Heo 600324a56e1STejun Heo kernfs_put(kn); 601fd7b9f7bSTejun Heo return ERR_PTR(rc); 602fd7b9f7bSTejun Heo } 603fd7b9f7bSTejun Heo 604c637b8acSTejun Heo static struct dentry *kernfs_iop_lookup(struct inode *dir, 605c637b8acSTejun Heo struct dentry *dentry, 606fd7b9f7bSTejun Heo unsigned int flags) 607fd7b9f7bSTejun Heo { 60819bbb926STejun Heo struct dentry *ret; 609324a56e1STejun Heo struct kernfs_node *parent = dentry->d_parent->d_fsdata; 610324a56e1STejun Heo struct kernfs_node *kn; 611fd7b9f7bSTejun Heo struct inode *inode; 612fd7b9f7bSTejun Heo const void *ns = NULL; 613fd7b9f7bSTejun Heo 614a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 615fd7b9f7bSTejun Heo 616324a56e1STejun Heo if (kernfs_ns_enabled(parent)) 617c525aaddSTejun Heo ns = kernfs_info(dir->i_sb)->ns; 618fd7b9f7bSTejun Heo 619324a56e1STejun Heo kn = kernfs_find_ns(parent, dentry->d_name.name, ns); 620fd7b9f7bSTejun Heo 621fd7b9f7bSTejun Heo /* no such entry */ 622324a56e1STejun Heo if (!kn) { 62319bbb926STejun Heo ret = NULL; 624fd7b9f7bSTejun Heo goto out_unlock; 625fd7b9f7bSTejun Heo } 626324a56e1STejun Heo kernfs_get(kn); 627324a56e1STejun Heo dentry->d_fsdata = kn; 628fd7b9f7bSTejun Heo 629fd7b9f7bSTejun Heo /* attach dentry and inode */ 630c637b8acSTejun Heo inode = kernfs_get_inode(dir->i_sb, kn); 631fd7b9f7bSTejun Heo if (!inode) { 632fd7b9f7bSTejun Heo ret = ERR_PTR(-ENOMEM); 633fd7b9f7bSTejun Heo goto out_unlock; 634fd7b9f7bSTejun Heo } 635fd7b9f7bSTejun Heo 636fd7b9f7bSTejun Heo /* instantiate and hash dentry */ 637fd7b9f7bSTejun Heo ret = d_materialise_unique(dentry, inode); 638fd7b9f7bSTejun Heo out_unlock: 639a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 640fd7b9f7bSTejun Heo return ret; 641fd7b9f7bSTejun Heo } 642fd7b9f7bSTejun Heo 64380b9bbefSTejun Heo static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry, 64480b9bbefSTejun Heo umode_t mode) 64580b9bbefSTejun Heo { 64680b9bbefSTejun Heo struct kernfs_node *parent = dir->i_private; 64780b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops; 64880b9bbefSTejun Heo 64980b9bbefSTejun Heo if (!kdops || !kdops->mkdir) 65080b9bbefSTejun Heo return -EPERM; 65180b9bbefSTejun Heo 65280b9bbefSTejun Heo return kdops->mkdir(parent, dentry->d_name.name, mode); 65380b9bbefSTejun Heo } 65480b9bbefSTejun Heo 65580b9bbefSTejun Heo static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) 65680b9bbefSTejun Heo { 65780b9bbefSTejun Heo struct kernfs_node *kn = dentry->d_fsdata; 65880b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops; 65980b9bbefSTejun Heo 66080b9bbefSTejun Heo if (!kdops || !kdops->rmdir) 66180b9bbefSTejun Heo return -EPERM; 66280b9bbefSTejun Heo 66380b9bbefSTejun Heo return kdops->rmdir(kn); 66480b9bbefSTejun Heo } 66580b9bbefSTejun Heo 66680b9bbefSTejun Heo static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry, 66780b9bbefSTejun Heo struct inode *new_dir, struct dentry *new_dentry) 66880b9bbefSTejun Heo { 66980b9bbefSTejun Heo struct kernfs_node *kn = old_dentry->d_fsdata; 67080b9bbefSTejun Heo struct kernfs_node *new_parent = new_dir->i_private; 67180b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops; 67280b9bbefSTejun Heo 67380b9bbefSTejun Heo if (!kdops || !kdops->rename) 67480b9bbefSTejun Heo return -EPERM; 67580b9bbefSTejun Heo 67680b9bbefSTejun Heo return kdops->rename(kn, new_parent, new_dentry->d_name.name); 67780b9bbefSTejun Heo } 67880b9bbefSTejun Heo 679a797bfc3STejun Heo const struct inode_operations kernfs_dir_iops = { 680c637b8acSTejun Heo .lookup = kernfs_iop_lookup, 681c637b8acSTejun Heo .permission = kernfs_iop_permission, 682c637b8acSTejun Heo .setattr = kernfs_iop_setattr, 683c637b8acSTejun Heo .getattr = kernfs_iop_getattr, 684c637b8acSTejun Heo .setxattr = kernfs_iop_setxattr, 685c637b8acSTejun Heo .removexattr = kernfs_iop_removexattr, 686c637b8acSTejun Heo .getxattr = kernfs_iop_getxattr, 687c637b8acSTejun Heo .listxattr = kernfs_iop_listxattr, 68880b9bbefSTejun Heo 68980b9bbefSTejun Heo .mkdir = kernfs_iop_mkdir, 69080b9bbefSTejun Heo .rmdir = kernfs_iop_rmdir, 69180b9bbefSTejun Heo .rename = kernfs_iop_rename, 692fd7b9f7bSTejun Heo }; 693fd7b9f7bSTejun Heo 694c637b8acSTejun Heo static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos) 695fd7b9f7bSTejun Heo { 696324a56e1STejun Heo struct kernfs_node *last; 697fd7b9f7bSTejun Heo 698fd7b9f7bSTejun Heo while (true) { 699fd7b9f7bSTejun Heo struct rb_node *rbn; 700fd7b9f7bSTejun Heo 701fd7b9f7bSTejun Heo last = pos; 702fd7b9f7bSTejun Heo 703df23fc39STejun Heo if (kernfs_type(pos) != KERNFS_DIR) 704fd7b9f7bSTejun Heo break; 705fd7b9f7bSTejun Heo 706adc5e8b5STejun Heo rbn = rb_first(&pos->dir.children); 707fd7b9f7bSTejun Heo if (!rbn) 708fd7b9f7bSTejun Heo break; 709fd7b9f7bSTejun Heo 710324a56e1STejun Heo pos = rb_to_kn(rbn); 711fd7b9f7bSTejun Heo } 712fd7b9f7bSTejun Heo 713fd7b9f7bSTejun Heo return last; 714fd7b9f7bSTejun Heo } 715fd7b9f7bSTejun Heo 716fd7b9f7bSTejun Heo /** 717c637b8acSTejun Heo * kernfs_next_descendant_post - find the next descendant for post-order walk 718fd7b9f7bSTejun Heo * @pos: the current position (%NULL to initiate traversal) 719324a56e1STejun Heo * @root: kernfs_node whose descendants to walk 720fd7b9f7bSTejun Heo * 721fd7b9f7bSTejun Heo * Find the next descendant to visit for post-order traversal of @root's 722fd7b9f7bSTejun Heo * descendants. @root is included in the iteration and the last node to be 723fd7b9f7bSTejun Heo * visited. 724fd7b9f7bSTejun Heo */ 725c637b8acSTejun Heo static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, 726324a56e1STejun Heo struct kernfs_node *root) 727fd7b9f7bSTejun Heo { 728fd7b9f7bSTejun Heo struct rb_node *rbn; 729fd7b9f7bSTejun Heo 730a797bfc3STejun Heo lockdep_assert_held(&kernfs_mutex); 731fd7b9f7bSTejun Heo 732fd7b9f7bSTejun Heo /* if first iteration, visit leftmost descendant which may be root */ 733fd7b9f7bSTejun Heo if (!pos) 734c637b8acSTejun Heo return kernfs_leftmost_descendant(root); 735fd7b9f7bSTejun Heo 736fd7b9f7bSTejun Heo /* if we visited @root, we're done */ 737fd7b9f7bSTejun Heo if (pos == root) 738fd7b9f7bSTejun Heo return NULL; 739fd7b9f7bSTejun Heo 740fd7b9f7bSTejun Heo /* if there's an unvisited sibling, visit its leftmost descendant */ 741adc5e8b5STejun Heo rbn = rb_next(&pos->rb); 742fd7b9f7bSTejun Heo if (rbn) 743c637b8acSTejun Heo return kernfs_leftmost_descendant(rb_to_kn(rbn)); 744fd7b9f7bSTejun Heo 745fd7b9f7bSTejun Heo /* no sibling left, visit parent */ 746adc5e8b5STejun Heo return pos->parent; 747fd7b9f7bSTejun Heo } 748fd7b9f7bSTejun Heo 749988cd7afSTejun Heo static void __kernfs_remove(struct kernfs_node *kn) 750fd7b9f7bSTejun Heo { 75135beab06STejun Heo struct kernfs_node *pos; 75235beab06STejun Heo 75335beab06STejun Heo lockdep_assert_held(&kernfs_mutex); 754fd7b9f7bSTejun Heo 755ce9b499cSGreg Kroah-Hartman if (!kn) 756ce9b499cSGreg Kroah-Hartman return; 757ce9b499cSGreg Kroah-Hartman 758c637b8acSTejun Heo pr_debug("kernfs %s: removing\n", kn->name); 759fd7b9f7bSTejun Heo 76035beab06STejun Heo /* disable lookup and node creation under @kn */ 76135beab06STejun Heo pos = NULL; 76235beab06STejun Heo while ((pos = kernfs_next_descendant_post(pos, kn))) 76335beab06STejun Heo pos->flags |= KERNFS_REMOVED; 76435beab06STejun Heo 76535beab06STejun Heo /* deactivate and unlink the subtree node-by-node */ 766fd7b9f7bSTejun Heo do { 76735beab06STejun Heo pos = kernfs_leftmost_descendant(kn); 76835beab06STejun Heo 76935beab06STejun Heo /* 77035beab06STejun Heo * kernfs_deactivate() drops kernfs_mutex temporarily and 77135beab06STejun Heo * @pos's base ref could have been put by someone else by 77235beab06STejun Heo * the time the function returns. Make sure it doesn't go 77335beab06STejun Heo * away underneath us. 77435beab06STejun Heo */ 77535beab06STejun Heo kernfs_get(pos); 77635beab06STejun Heo 77735beab06STejun Heo kernfs_deactivate(pos); 77835beab06STejun Heo 77935beab06STejun Heo /* 78035beab06STejun Heo * kernfs_unlink_sibling() succeeds once per node. Use it 78135beab06STejun Heo * to decide who's responsible for cleanups. 78235beab06STejun Heo */ 78335beab06STejun Heo if (!pos->parent || kernfs_unlink_sibling(pos)) { 78435beab06STejun Heo struct kernfs_iattrs *ps_iattr = 78535beab06STejun Heo pos->parent ? pos->parent->iattr : NULL; 78635beab06STejun Heo 78735beab06STejun Heo /* update timestamps on the parent */ 78835beab06STejun Heo if (ps_iattr) { 78935beab06STejun Heo ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME; 79035beab06STejun Heo ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME; 79135beab06STejun Heo } 79235beab06STejun Heo 793988cd7afSTejun Heo kernfs_put(pos); 79435beab06STejun Heo } 79535beab06STejun Heo 79635beab06STejun Heo kernfs_put(pos); 79735beab06STejun Heo } while (pos != kn); 798fd7b9f7bSTejun Heo } 799fd7b9f7bSTejun Heo 800fd7b9f7bSTejun Heo /** 801324a56e1STejun Heo * kernfs_remove - remove a kernfs_node recursively 802324a56e1STejun Heo * @kn: the kernfs_node to remove 803fd7b9f7bSTejun Heo * 804324a56e1STejun Heo * Remove @kn along with all its subdirectories and files. 805fd7b9f7bSTejun Heo */ 806324a56e1STejun Heo void kernfs_remove(struct kernfs_node *kn) 807fd7b9f7bSTejun Heo { 808988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 809988cd7afSTejun Heo __kernfs_remove(kn); 810988cd7afSTejun Heo mutex_unlock(&kernfs_mutex); 811fd7b9f7bSTejun Heo } 812fd7b9f7bSTejun Heo 813fd7b9f7bSTejun Heo /** 814324a56e1STejun Heo * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it 815324a56e1STejun Heo * @parent: parent of the target 816324a56e1STejun Heo * @name: name of the kernfs_node to remove 817324a56e1STejun Heo * @ns: namespace tag of the kernfs_node to remove 818fd7b9f7bSTejun Heo * 819324a56e1STejun Heo * Look for the kernfs_node with @name and @ns under @parent and remove it. 820324a56e1STejun Heo * Returns 0 on success, -ENOENT if such entry doesn't exist. 821fd7b9f7bSTejun Heo */ 822324a56e1STejun Heo int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, 823fd7b9f7bSTejun Heo const void *ns) 824fd7b9f7bSTejun Heo { 825324a56e1STejun Heo struct kernfs_node *kn; 826fd7b9f7bSTejun Heo 827324a56e1STejun Heo if (!parent) { 828c637b8acSTejun Heo WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n", 829fd7b9f7bSTejun Heo name); 830fd7b9f7bSTejun Heo return -ENOENT; 831fd7b9f7bSTejun Heo } 832fd7b9f7bSTejun Heo 833988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 834fd7b9f7bSTejun Heo 835324a56e1STejun Heo kn = kernfs_find_ns(parent, name, ns); 836324a56e1STejun Heo if (kn) 837988cd7afSTejun Heo __kernfs_remove(kn); 838fd7b9f7bSTejun Heo 839988cd7afSTejun Heo mutex_unlock(&kernfs_mutex); 840fd7b9f7bSTejun Heo 841324a56e1STejun Heo if (kn) 842fd7b9f7bSTejun Heo return 0; 843fd7b9f7bSTejun Heo else 844fd7b9f7bSTejun Heo return -ENOENT; 845fd7b9f7bSTejun Heo } 846fd7b9f7bSTejun Heo 847fd7b9f7bSTejun Heo /** 848fd7b9f7bSTejun Heo * kernfs_rename_ns - move and rename a kernfs_node 849324a56e1STejun Heo * @kn: target node 850fd7b9f7bSTejun Heo * @new_parent: new parent to put @sd under 851fd7b9f7bSTejun Heo * @new_name: new name 852fd7b9f7bSTejun Heo * @new_ns: new namespace tag 853fd7b9f7bSTejun Heo */ 854324a56e1STejun Heo int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, 855fd7b9f7bSTejun Heo const char *new_name, const void *new_ns) 856fd7b9f7bSTejun Heo { 857fd7b9f7bSTejun Heo int error; 858fd7b9f7bSTejun Heo 859ae34372eSTejun Heo mutex_lock(&kernfs_mutex); 860d0ae3d43STejun Heo 861798c75a0SGreg Kroah-Hartman error = -ENOENT; 862798c75a0SGreg Kroah-Hartman if ((kn->flags | new_parent->flags) & KERNFS_REMOVED) 863798c75a0SGreg Kroah-Hartman goto out; 864798c75a0SGreg Kroah-Hartman 865fd7b9f7bSTejun Heo error = 0; 866adc5e8b5STejun Heo if ((kn->parent == new_parent) && (kn->ns == new_ns) && 867adc5e8b5STejun Heo (strcmp(kn->name, new_name) == 0)) 868798c75a0SGreg Kroah-Hartman goto out; /* nothing to rename */ 869fd7b9f7bSTejun Heo 870fd7b9f7bSTejun Heo error = -EEXIST; 871fd7b9f7bSTejun Heo if (kernfs_find_ns(new_parent, new_name, new_ns)) 872798c75a0SGreg Kroah-Hartman goto out; 873fd7b9f7bSTejun Heo 874324a56e1STejun Heo /* rename kernfs_node */ 875adc5e8b5STejun Heo if (strcmp(kn->name, new_name) != 0) { 876fd7b9f7bSTejun Heo error = -ENOMEM; 877fd7b9f7bSTejun Heo new_name = kstrdup(new_name, GFP_KERNEL); 878fd7b9f7bSTejun Heo if (!new_name) 879798c75a0SGreg Kroah-Hartman goto out; 880fd7b9f7bSTejun Heo 88147a52e91STejun Heo if (kn->flags & KERNFS_STATIC_NAME) 88247a52e91STejun Heo kn->flags &= ~KERNFS_STATIC_NAME; 88347a52e91STejun Heo else 884adc5e8b5STejun Heo kfree(kn->name); 88547a52e91STejun Heo 886adc5e8b5STejun Heo kn->name = new_name; 887fd7b9f7bSTejun Heo } 888fd7b9f7bSTejun Heo 889fd7b9f7bSTejun Heo /* 890fd7b9f7bSTejun Heo * Move to the appropriate place in the appropriate directories rbtree. 891fd7b9f7bSTejun Heo */ 892c637b8acSTejun Heo kernfs_unlink_sibling(kn); 893fd7b9f7bSTejun Heo kernfs_get(new_parent); 894adc5e8b5STejun Heo kernfs_put(kn->parent); 895adc5e8b5STejun Heo kn->ns = new_ns; 896c637b8acSTejun Heo kn->hash = kernfs_name_hash(kn->name, kn->ns); 897adc5e8b5STejun Heo kn->parent = new_parent; 898c637b8acSTejun Heo kernfs_link_sibling(kn); 899fd7b9f7bSTejun Heo 900fd7b9f7bSTejun Heo error = 0; 901ae34372eSTejun Heo out: 902798c75a0SGreg Kroah-Hartman mutex_unlock(&kernfs_mutex); 903fd7b9f7bSTejun Heo return error; 904fd7b9f7bSTejun Heo } 905fd7b9f7bSTejun Heo 906fd7b9f7bSTejun Heo /* Relationship between s_mode and the DT_xxx types */ 907324a56e1STejun Heo static inline unsigned char dt_type(struct kernfs_node *kn) 908fd7b9f7bSTejun Heo { 909adc5e8b5STejun Heo return (kn->mode >> 12) & 15; 910fd7b9f7bSTejun Heo } 911fd7b9f7bSTejun Heo 912c637b8acSTejun Heo static int kernfs_dir_fop_release(struct inode *inode, struct file *filp) 913fd7b9f7bSTejun Heo { 914fd7b9f7bSTejun Heo kernfs_put(filp->private_data); 915fd7b9f7bSTejun Heo return 0; 916fd7b9f7bSTejun Heo } 917fd7b9f7bSTejun Heo 918c637b8acSTejun Heo static struct kernfs_node *kernfs_dir_pos(const void *ns, 919324a56e1STejun Heo struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) 920fd7b9f7bSTejun Heo { 921fd7b9f7bSTejun Heo if (pos) { 922798c75a0SGreg Kroah-Hartman int valid = !(pos->flags & KERNFS_REMOVED) && 923798c75a0SGreg Kroah-Hartman pos->parent == parent && hash == pos->hash; 924fd7b9f7bSTejun Heo kernfs_put(pos); 925fd7b9f7bSTejun Heo if (!valid) 926fd7b9f7bSTejun Heo pos = NULL; 927fd7b9f7bSTejun Heo } 928fd7b9f7bSTejun Heo if (!pos && (hash > 1) && (hash < INT_MAX)) { 929adc5e8b5STejun Heo struct rb_node *node = parent->dir.children.rb_node; 930fd7b9f7bSTejun Heo while (node) { 931324a56e1STejun Heo pos = rb_to_kn(node); 932fd7b9f7bSTejun Heo 933adc5e8b5STejun Heo if (hash < pos->hash) 934fd7b9f7bSTejun Heo node = node->rb_left; 935adc5e8b5STejun Heo else if (hash > pos->hash) 936fd7b9f7bSTejun Heo node = node->rb_right; 937fd7b9f7bSTejun Heo else 938fd7b9f7bSTejun Heo break; 939fd7b9f7bSTejun Heo } 940fd7b9f7bSTejun Heo } 941fd7b9f7bSTejun Heo /* Skip over entries in the wrong namespace */ 942adc5e8b5STejun Heo while (pos && pos->ns != ns) { 943adc5e8b5STejun Heo struct rb_node *node = rb_next(&pos->rb); 944fd7b9f7bSTejun Heo if (!node) 945fd7b9f7bSTejun Heo pos = NULL; 946fd7b9f7bSTejun Heo else 947324a56e1STejun Heo pos = rb_to_kn(node); 948fd7b9f7bSTejun Heo } 949fd7b9f7bSTejun Heo return pos; 950fd7b9f7bSTejun Heo } 951fd7b9f7bSTejun Heo 952c637b8acSTejun Heo static struct kernfs_node *kernfs_dir_next_pos(const void *ns, 953324a56e1STejun Heo struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos) 954fd7b9f7bSTejun Heo { 955c637b8acSTejun Heo pos = kernfs_dir_pos(ns, parent, ino, pos); 956fd7b9f7bSTejun Heo if (pos) 957fd7b9f7bSTejun Heo do { 958adc5e8b5STejun Heo struct rb_node *node = rb_next(&pos->rb); 959fd7b9f7bSTejun Heo if (!node) 960fd7b9f7bSTejun Heo pos = NULL; 961fd7b9f7bSTejun Heo else 962324a56e1STejun Heo pos = rb_to_kn(node); 963adc5e8b5STejun Heo } while (pos && pos->ns != ns); 964fd7b9f7bSTejun Heo return pos; 965fd7b9f7bSTejun Heo } 966fd7b9f7bSTejun Heo 967c637b8acSTejun Heo static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) 968fd7b9f7bSTejun Heo { 969fd7b9f7bSTejun Heo struct dentry *dentry = file->f_path.dentry; 970324a56e1STejun Heo struct kernfs_node *parent = dentry->d_fsdata; 971324a56e1STejun Heo struct kernfs_node *pos = file->private_data; 972fd7b9f7bSTejun Heo const void *ns = NULL; 973fd7b9f7bSTejun Heo 974fd7b9f7bSTejun Heo if (!dir_emit_dots(file, ctx)) 975fd7b9f7bSTejun Heo return 0; 976a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 977fd7b9f7bSTejun Heo 978324a56e1STejun Heo if (kernfs_ns_enabled(parent)) 979c525aaddSTejun Heo ns = kernfs_info(dentry->d_sb)->ns; 980fd7b9f7bSTejun Heo 981c637b8acSTejun Heo for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos); 982fd7b9f7bSTejun Heo pos; 983c637b8acSTejun Heo pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) { 984adc5e8b5STejun Heo const char *name = pos->name; 985fd7b9f7bSTejun Heo unsigned int type = dt_type(pos); 986fd7b9f7bSTejun Heo int len = strlen(name); 987adc5e8b5STejun Heo ino_t ino = pos->ino; 988fd7b9f7bSTejun Heo 989adc5e8b5STejun Heo ctx->pos = pos->hash; 990fd7b9f7bSTejun Heo file->private_data = pos; 991fd7b9f7bSTejun Heo kernfs_get(pos); 992fd7b9f7bSTejun Heo 993a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 994fd7b9f7bSTejun Heo if (!dir_emit(ctx, name, len, ino, type)) 995fd7b9f7bSTejun Heo return 0; 996a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 997fd7b9f7bSTejun Heo } 998a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 999fd7b9f7bSTejun Heo file->private_data = NULL; 1000fd7b9f7bSTejun Heo ctx->pos = INT_MAX; 1001fd7b9f7bSTejun Heo return 0; 1002fd7b9f7bSTejun Heo } 1003fd7b9f7bSTejun Heo 1004c637b8acSTejun Heo static loff_t kernfs_dir_fop_llseek(struct file *file, loff_t offset, 1005c637b8acSTejun Heo int whence) 1006fd7b9f7bSTejun Heo { 1007fd7b9f7bSTejun Heo struct inode *inode = file_inode(file); 1008fd7b9f7bSTejun Heo loff_t ret; 1009fd7b9f7bSTejun Heo 1010fd7b9f7bSTejun Heo mutex_lock(&inode->i_mutex); 1011fd7b9f7bSTejun Heo ret = generic_file_llseek(file, offset, whence); 1012fd7b9f7bSTejun Heo mutex_unlock(&inode->i_mutex); 1013fd7b9f7bSTejun Heo 1014fd7b9f7bSTejun Heo return ret; 1015fd7b9f7bSTejun Heo } 1016fd7b9f7bSTejun Heo 1017a797bfc3STejun Heo const struct file_operations kernfs_dir_fops = { 1018fd7b9f7bSTejun Heo .read = generic_read_dir, 1019c637b8acSTejun Heo .iterate = kernfs_fop_readdir, 1020c637b8acSTejun Heo .release = kernfs_dir_fop_release, 1021c637b8acSTejun Heo .llseek = kernfs_dir_fop_llseek, 1022fd7b9f7bSTejun Heo }; 1023