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 25182fd64bSTejun Heo static bool kernfs_lockdep(struct kernfs_node *kn) 26182fd64bSTejun Heo { 27182fd64bSTejun Heo #ifdef CONFIG_DEBUG_LOCK_ALLOC 28182fd64bSTejun Heo return kn->flags & KERNFS_LOCKDEP; 29182fd64bSTejun Heo #else 30182fd64bSTejun Heo return false; 31182fd64bSTejun Heo #endif 32182fd64bSTejun Heo } 33182fd64bSTejun Heo 34fd7b9f7bSTejun Heo /** 35c637b8acSTejun Heo * kernfs_name_hash 36fd7b9f7bSTejun Heo * @name: Null terminated string to hash 37fd7b9f7bSTejun Heo * @ns: Namespace tag to hash 38fd7b9f7bSTejun Heo * 39fd7b9f7bSTejun Heo * Returns 31 bit hash of ns + name (so it fits in an off_t ) 40fd7b9f7bSTejun Heo */ 41c637b8acSTejun Heo static unsigned int kernfs_name_hash(const char *name, const void *ns) 42fd7b9f7bSTejun Heo { 43fd7b9f7bSTejun Heo unsigned long hash = init_name_hash(); 44fd7b9f7bSTejun Heo unsigned int len = strlen(name); 45fd7b9f7bSTejun Heo while (len--) 46fd7b9f7bSTejun Heo hash = partial_name_hash(*name++, hash); 47fd7b9f7bSTejun Heo hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31)); 48fd7b9f7bSTejun Heo hash &= 0x7fffffffU; 49fd7b9f7bSTejun Heo /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ 50fd7b9f7bSTejun Heo if (hash < 1) 51fd7b9f7bSTejun Heo hash += 2; 52fd7b9f7bSTejun Heo if (hash >= INT_MAX) 53fd7b9f7bSTejun Heo hash = INT_MAX - 1; 54fd7b9f7bSTejun Heo return hash; 55fd7b9f7bSTejun Heo } 56fd7b9f7bSTejun Heo 57c637b8acSTejun Heo static int kernfs_name_compare(unsigned int hash, const char *name, 58324a56e1STejun Heo const void *ns, const struct kernfs_node *kn) 59fd7b9f7bSTejun Heo { 60adc5e8b5STejun Heo if (hash != kn->hash) 61adc5e8b5STejun Heo return hash - kn->hash; 62adc5e8b5STejun Heo if (ns != kn->ns) 63adc5e8b5STejun Heo return ns - kn->ns; 64adc5e8b5STejun Heo return strcmp(name, kn->name); 65fd7b9f7bSTejun Heo } 66fd7b9f7bSTejun Heo 67c637b8acSTejun Heo static int kernfs_sd_compare(const struct kernfs_node *left, 68324a56e1STejun Heo const struct kernfs_node *right) 69fd7b9f7bSTejun Heo { 70c637b8acSTejun Heo return kernfs_name_compare(left->hash, left->name, left->ns, right); 71fd7b9f7bSTejun Heo } 72fd7b9f7bSTejun Heo 73fd7b9f7bSTejun Heo /** 74c637b8acSTejun Heo * kernfs_link_sibling - link kernfs_node into sibling rbtree 75324a56e1STejun Heo * @kn: kernfs_node of interest 76fd7b9f7bSTejun Heo * 77324a56e1STejun Heo * Link @kn into its sibling rbtree which starts from 78adc5e8b5STejun Heo * @kn->parent->dir.children. 79fd7b9f7bSTejun Heo * 80fd7b9f7bSTejun Heo * Locking: 81a797bfc3STejun Heo * mutex_lock(kernfs_mutex) 82fd7b9f7bSTejun Heo * 83fd7b9f7bSTejun Heo * RETURNS: 84fd7b9f7bSTejun Heo * 0 on susccess -EEXIST on failure. 85fd7b9f7bSTejun Heo */ 86c637b8acSTejun Heo static int kernfs_link_sibling(struct kernfs_node *kn) 87fd7b9f7bSTejun Heo { 88adc5e8b5STejun Heo struct rb_node **node = &kn->parent->dir.children.rb_node; 89fd7b9f7bSTejun Heo struct rb_node *parent = NULL; 90fd7b9f7bSTejun Heo 91df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_DIR) 92adc5e8b5STejun Heo kn->parent->dir.subdirs++; 93fd7b9f7bSTejun Heo 94fd7b9f7bSTejun Heo while (*node) { 95324a56e1STejun Heo struct kernfs_node *pos; 96fd7b9f7bSTejun Heo int result; 97fd7b9f7bSTejun Heo 98324a56e1STejun Heo pos = rb_to_kn(*node); 99fd7b9f7bSTejun Heo parent = *node; 100c637b8acSTejun Heo result = kernfs_sd_compare(kn, pos); 101fd7b9f7bSTejun Heo if (result < 0) 102adc5e8b5STejun Heo node = &pos->rb.rb_left; 103fd7b9f7bSTejun Heo else if (result > 0) 104adc5e8b5STejun Heo node = &pos->rb.rb_right; 105fd7b9f7bSTejun Heo else 106fd7b9f7bSTejun Heo return -EEXIST; 107fd7b9f7bSTejun Heo } 108fd7b9f7bSTejun Heo /* add new node and rebalance the tree */ 109adc5e8b5STejun Heo rb_link_node(&kn->rb, parent, node); 110adc5e8b5STejun Heo rb_insert_color(&kn->rb, &kn->parent->dir.children); 111fd7b9f7bSTejun Heo return 0; 112fd7b9f7bSTejun Heo } 113fd7b9f7bSTejun Heo 114fd7b9f7bSTejun Heo /** 115c637b8acSTejun Heo * kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree 116324a56e1STejun Heo * @kn: kernfs_node of interest 117fd7b9f7bSTejun Heo * 11835beab06STejun Heo * Try to unlink @kn from its sibling rbtree which starts from 11935beab06STejun Heo * kn->parent->dir.children. Returns %true if @kn was actually 12035beab06STejun Heo * removed, %false if @kn wasn't on the rbtree. 121fd7b9f7bSTejun Heo * 122fd7b9f7bSTejun Heo * Locking: 123a797bfc3STejun Heo * mutex_lock(kernfs_mutex) 124fd7b9f7bSTejun Heo */ 12535beab06STejun Heo static bool kernfs_unlink_sibling(struct kernfs_node *kn) 126fd7b9f7bSTejun Heo { 12735beab06STejun Heo if (RB_EMPTY_NODE(&kn->rb)) 12835beab06STejun Heo return false; 12935beab06STejun Heo 130df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_DIR) 131adc5e8b5STejun Heo kn->parent->dir.subdirs--; 132fd7b9f7bSTejun Heo 133adc5e8b5STejun Heo rb_erase(&kn->rb, &kn->parent->dir.children); 13435beab06STejun Heo RB_CLEAR_NODE(&kn->rb); 13535beab06STejun Heo return true; 136fd7b9f7bSTejun Heo } 137fd7b9f7bSTejun Heo 138fd7b9f7bSTejun Heo /** 139c637b8acSTejun Heo * kernfs_get_active - get an active reference to kernfs_node 140324a56e1STejun Heo * @kn: kernfs_node to get an active reference to 141fd7b9f7bSTejun Heo * 142324a56e1STejun Heo * Get an active reference of @kn. This function is noop if @kn 143fd7b9f7bSTejun Heo * is NULL. 144fd7b9f7bSTejun Heo * 145fd7b9f7bSTejun Heo * RETURNS: 146324a56e1STejun Heo * Pointer to @kn on success, NULL on failure. 147fd7b9f7bSTejun Heo */ 148c637b8acSTejun Heo struct kernfs_node *kernfs_get_active(struct kernfs_node *kn) 149fd7b9f7bSTejun Heo { 150324a56e1STejun Heo if (unlikely(!kn)) 151fd7b9f7bSTejun Heo return NULL; 152fd7b9f7bSTejun Heo 153f4b3e631SGreg Kroah-Hartman if (!atomic_inc_unless_negative(&kn->active)) 154f4b3e631SGreg Kroah-Hartman return NULL; 155f4b3e631SGreg Kroah-Hartman 156182fd64bSTejun Heo if (kernfs_lockdep(kn)) 157324a56e1STejun Heo rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); 158324a56e1STejun Heo return kn; 159fd7b9f7bSTejun Heo } 160fd7b9f7bSTejun Heo 161fd7b9f7bSTejun Heo /** 162c637b8acSTejun Heo * kernfs_put_active - put an active reference to kernfs_node 163324a56e1STejun Heo * @kn: kernfs_node to put an active reference to 164fd7b9f7bSTejun Heo * 165324a56e1STejun Heo * Put an active reference to @kn. This function is noop if @kn 166fd7b9f7bSTejun Heo * is NULL. 167fd7b9f7bSTejun Heo */ 168c637b8acSTejun Heo void kernfs_put_active(struct kernfs_node *kn) 169fd7b9f7bSTejun Heo { 170abd54f02STejun Heo struct kernfs_root *root = kernfs_root(kn); 171fd7b9f7bSTejun Heo int v; 172fd7b9f7bSTejun Heo 173324a56e1STejun Heo if (unlikely(!kn)) 174fd7b9f7bSTejun Heo return; 175fd7b9f7bSTejun Heo 176182fd64bSTejun Heo if (kernfs_lockdep(kn)) 177324a56e1STejun Heo rwsem_release(&kn->dep_map, 1, _RET_IP_); 178adc5e8b5STejun Heo v = atomic_dec_return(&kn->active); 179df23fc39STejun Heo if (likely(v != KN_DEACTIVATED_BIAS)) 180fd7b9f7bSTejun Heo return; 181fd7b9f7bSTejun Heo 182abd54f02STejun Heo wake_up_all(&root->deactivate_waitq); 183fd7b9f7bSTejun Heo } 184fd7b9f7bSTejun Heo 185fd7b9f7bSTejun Heo /** 186798c75a0SGreg Kroah-Hartman * kernfs_deactivate - deactivate kernfs_node 187798c75a0SGreg Kroah-Hartman * @kn: kernfs_node to deactivate 188fd7b9f7bSTejun Heo * 189ccf02aafSTejun Heo * Deny new active references, drain existing ones and nuke all 190ccf02aafSTejun Heo * existing mmaps. Mutiple removers may invoke this function 191ccf02aafSTejun Heo * concurrently on @kn and all will return after deactivation and 192ccf02aafSTejun Heo * draining are complete. 193fd7b9f7bSTejun Heo */ 194798c75a0SGreg Kroah-Hartman static void kernfs_deactivate(struct kernfs_node *kn) 19535beab06STejun Heo __releases(&kernfs_mutex) __acquires(&kernfs_mutex) 196fd7b9f7bSTejun Heo { 197abd54f02STejun Heo struct kernfs_root *root = kernfs_root(kn); 198fd7b9f7bSTejun Heo 19935beab06STejun Heo lockdep_assert_held(&kernfs_mutex); 200798c75a0SGreg Kroah-Hartman BUG_ON(!(kn->flags & KERNFS_REMOVED)); 201798c75a0SGreg Kroah-Hartman 20235beab06STejun Heo /* only the first invocation on @kn should deactivate it */ 20335beab06STejun Heo if (atomic_read(&kn->active) >= 0) 204abd54f02STejun Heo atomic_add(KN_DEACTIVATED_BIAS, &kn->active); 205abd54f02STejun Heo 20635beab06STejun Heo mutex_unlock(&kernfs_mutex); 207abd54f02STejun Heo 208182fd64bSTejun Heo if (kernfs_lockdep(kn)) { 20935beab06STejun Heo rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); 21035beab06STejun Heo if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) 21135beab06STejun Heo lock_contended(&kn->dep_map, _RET_IP_); 21235beab06STejun Heo } 21335beab06STejun Heo 21435beab06STejun Heo /* but everyone should wait for draining */ 215abd54f02STejun Heo wait_event(root->deactivate_waitq, 216abd54f02STejun Heo atomic_read(&kn->active) == KN_DEACTIVATED_BIAS); 217fd7b9f7bSTejun Heo 218182fd64bSTejun Heo if (kernfs_lockdep(kn)) { 219324a56e1STejun Heo lock_acquired(&kn->dep_map, _RET_IP_); 220324a56e1STejun Heo rwsem_release(&kn->dep_map, 1, _RET_IP_); 221fd7b9f7bSTejun Heo } 22235beab06STejun Heo 223ccf02aafSTejun Heo kernfs_unmap_bin_file(kn); 224ccf02aafSTejun Heo 22535beab06STejun Heo mutex_lock(&kernfs_mutex); 226a6607930STejun Heo } 227fd7b9f7bSTejun Heo 228fd7b9f7bSTejun Heo /** 229324a56e1STejun Heo * kernfs_get - get a reference count on a kernfs_node 230324a56e1STejun Heo * @kn: the target kernfs_node 231fd7b9f7bSTejun Heo */ 232324a56e1STejun Heo void kernfs_get(struct kernfs_node *kn) 233fd7b9f7bSTejun Heo { 234324a56e1STejun Heo if (kn) { 235adc5e8b5STejun Heo WARN_ON(!atomic_read(&kn->count)); 236adc5e8b5STejun Heo atomic_inc(&kn->count); 237fd7b9f7bSTejun Heo } 238fd7b9f7bSTejun Heo } 239fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_get); 240fd7b9f7bSTejun Heo 241fd7b9f7bSTejun Heo /** 242324a56e1STejun Heo * kernfs_put - put a reference count on a kernfs_node 243324a56e1STejun Heo * @kn: the target kernfs_node 244fd7b9f7bSTejun Heo * 245324a56e1STejun Heo * Put a reference count of @kn and destroy it if it reached zero. 246fd7b9f7bSTejun Heo */ 247324a56e1STejun Heo void kernfs_put(struct kernfs_node *kn) 248fd7b9f7bSTejun Heo { 249324a56e1STejun Heo struct kernfs_node *parent; 250ba7443bcSTejun Heo struct kernfs_root *root; 251fd7b9f7bSTejun Heo 252adc5e8b5STejun Heo if (!kn || !atomic_dec_and_test(&kn->count)) 253fd7b9f7bSTejun Heo return; 254324a56e1STejun Heo root = kernfs_root(kn); 255fd7b9f7bSTejun Heo repeat: 256798c75a0SGreg Kroah-Hartman /* Moving/renaming is always done while holding reference. 257adc5e8b5STejun Heo * kn->parent won't change beneath us. 258fd7b9f7bSTejun Heo */ 259adc5e8b5STejun Heo parent = kn->parent; 260fd7b9f7bSTejun Heo 261798c75a0SGreg Kroah-Hartman WARN(!(kn->flags & KERNFS_REMOVED), "kernfs: free using entry: %s/%s\n", 262798c75a0SGreg Kroah-Hartman parent ? parent->name : "", kn->name); 263fd7b9f7bSTejun Heo 264df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_LINK) 265adc5e8b5STejun Heo kernfs_put(kn->symlink.target_kn); 2662063d608STejun Heo if (!(kn->flags & KERNFS_STATIC_NAME)) 267adc5e8b5STejun Heo kfree(kn->name); 268adc5e8b5STejun Heo if (kn->iattr) { 269adc5e8b5STejun Heo if (kn->iattr->ia_secdata) 270adc5e8b5STejun Heo security_release_secctx(kn->iattr->ia_secdata, 271adc5e8b5STejun Heo kn->iattr->ia_secdata_len); 272adc5e8b5STejun Heo simple_xattrs_free(&kn->iattr->xattrs); 2732322392bSTejun Heo } 274adc5e8b5STejun Heo kfree(kn->iattr); 275adc5e8b5STejun Heo ida_simple_remove(&root->ino_ida, kn->ino); 276a797bfc3STejun Heo kmem_cache_free(kernfs_node_cache, kn); 277fd7b9f7bSTejun Heo 278324a56e1STejun Heo kn = parent; 279324a56e1STejun Heo if (kn) { 280adc5e8b5STejun Heo if (atomic_dec_and_test(&kn->count)) 281fd7b9f7bSTejun Heo goto repeat; 282ba7443bcSTejun Heo } else { 283324a56e1STejun Heo /* just released the root kn, free @root too */ 284bc755553STejun Heo ida_destroy(&root->ino_ida); 285ba7443bcSTejun Heo kfree(root); 286ba7443bcSTejun Heo } 287fd7b9f7bSTejun Heo } 288fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_put); 289fd7b9f7bSTejun Heo 290c637b8acSTejun Heo static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) 291fd7b9f7bSTejun Heo { 292324a56e1STejun Heo struct kernfs_node *kn; 293fd7b9f7bSTejun Heo 294fd7b9f7bSTejun Heo if (flags & LOOKUP_RCU) 295fd7b9f7bSTejun Heo return -ECHILD; 296fd7b9f7bSTejun Heo 29719bbb926STejun Heo /* Always perform fresh lookup for negatives */ 29819bbb926STejun Heo if (!dentry->d_inode) 29919bbb926STejun Heo goto out_bad_unlocked; 30019bbb926STejun Heo 301324a56e1STejun Heo kn = dentry->d_fsdata; 302a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 303fd7b9f7bSTejun Heo 304798c75a0SGreg Kroah-Hartman /* The kernfs node has been deleted */ 305798c75a0SGreg Kroah-Hartman if (kn->flags & KERNFS_REMOVED) 306fd7b9f7bSTejun Heo goto out_bad; 307fd7b9f7bSTejun Heo 308c637b8acSTejun Heo /* The kernfs node has been moved? */ 309adc5e8b5STejun Heo if (dentry->d_parent->d_fsdata != kn->parent) 310fd7b9f7bSTejun Heo goto out_bad; 311fd7b9f7bSTejun Heo 312c637b8acSTejun Heo /* The kernfs node has been renamed */ 313adc5e8b5STejun Heo if (strcmp(dentry->d_name.name, kn->name) != 0) 314fd7b9f7bSTejun Heo goto out_bad; 315fd7b9f7bSTejun Heo 316c637b8acSTejun Heo /* The kernfs node has been moved to a different namespace */ 317adc5e8b5STejun Heo if (kn->parent && kernfs_ns_enabled(kn->parent) && 318c525aaddSTejun Heo kernfs_info(dentry->d_sb)->ns != kn->ns) 319fd7b9f7bSTejun Heo goto out_bad; 320fd7b9f7bSTejun Heo 321a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 322fd7b9f7bSTejun Heo out_valid: 323fd7b9f7bSTejun Heo return 1; 324fd7b9f7bSTejun Heo out_bad: 325a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 32619bbb926STejun Heo out_bad_unlocked: 32719bbb926STejun Heo /* 32819bbb926STejun Heo * @dentry doesn't match the underlying kernfs node, drop the 32919bbb926STejun Heo * dentry and force lookup. If we have submounts we must allow the 33019bbb926STejun Heo * vfs caches to lie about the state of the filesystem to prevent 33119bbb926STejun Heo * leaks and other nasty things, so use check_submounts_and_drop() 33219bbb926STejun Heo * instead of d_drop(). 333fd7b9f7bSTejun Heo */ 334fd7b9f7bSTejun Heo if (check_submounts_and_drop(dentry) != 0) 335fd7b9f7bSTejun Heo goto out_valid; 336fd7b9f7bSTejun Heo 337fd7b9f7bSTejun Heo return 0; 338fd7b9f7bSTejun Heo } 339fd7b9f7bSTejun Heo 340c637b8acSTejun Heo static void kernfs_dop_release(struct dentry *dentry) 341fd7b9f7bSTejun Heo { 342fd7b9f7bSTejun Heo kernfs_put(dentry->d_fsdata); 343fd7b9f7bSTejun Heo } 344fd7b9f7bSTejun Heo 345a797bfc3STejun Heo const struct dentry_operations kernfs_dops = { 346c637b8acSTejun Heo .d_revalidate = kernfs_dop_revalidate, 347c637b8acSTejun Heo .d_release = kernfs_dop_release, 348fd7b9f7bSTejun Heo }; 349fd7b9f7bSTejun Heo 350db4aad20STejun Heo static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, 351db4aad20STejun Heo const char *name, umode_t mode, 352db4aad20STejun Heo unsigned flags) 353fd7b9f7bSTejun Heo { 354fd7b9f7bSTejun Heo char *dup_name = NULL; 355324a56e1STejun Heo struct kernfs_node *kn; 356bc755553STejun Heo int ret; 357fd7b9f7bSTejun Heo 3582063d608STejun Heo if (!(flags & KERNFS_STATIC_NAME)) { 359fd7b9f7bSTejun Heo name = dup_name = kstrdup(name, GFP_KERNEL); 360fd7b9f7bSTejun Heo if (!name) 361fd7b9f7bSTejun Heo return NULL; 362fd7b9f7bSTejun Heo } 363fd7b9f7bSTejun Heo 364a797bfc3STejun Heo kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL); 365324a56e1STejun Heo if (!kn) 366fd7b9f7bSTejun Heo goto err_out1; 367fd7b9f7bSTejun Heo 368bc755553STejun Heo ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL); 369bc755553STejun Heo if (ret < 0) 370fd7b9f7bSTejun Heo goto err_out2; 371adc5e8b5STejun Heo kn->ino = ret; 372fd7b9f7bSTejun Heo 373adc5e8b5STejun Heo atomic_set(&kn->count, 1); 374798c75a0SGreg Kroah-Hartman atomic_set(&kn->active, 0); 37535beab06STejun Heo RB_CLEAR_NODE(&kn->rb); 376fd7b9f7bSTejun Heo 377adc5e8b5STejun Heo kn->name = name; 378adc5e8b5STejun Heo kn->mode = mode; 379798c75a0SGreg Kroah-Hartman kn->flags = flags | KERNFS_REMOVED; 380fd7b9f7bSTejun Heo 381324a56e1STejun Heo return kn; 382fd7b9f7bSTejun Heo 383fd7b9f7bSTejun Heo err_out2: 384a797bfc3STejun Heo kmem_cache_free(kernfs_node_cache, kn); 385fd7b9f7bSTejun Heo err_out1: 386fd7b9f7bSTejun Heo kfree(dup_name); 387fd7b9f7bSTejun Heo return NULL; 388fd7b9f7bSTejun Heo } 389fd7b9f7bSTejun Heo 390db4aad20STejun Heo struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, 391db4aad20STejun Heo const char *name, umode_t mode, 392db4aad20STejun Heo unsigned flags) 393db4aad20STejun Heo { 394db4aad20STejun Heo struct kernfs_node *kn; 395db4aad20STejun Heo 396db4aad20STejun Heo kn = __kernfs_new_node(kernfs_root(parent), name, mode, flags); 397db4aad20STejun Heo if (kn) { 398db4aad20STejun Heo kernfs_get(parent); 399db4aad20STejun Heo kn->parent = parent; 400db4aad20STejun Heo } 401db4aad20STejun Heo return kn; 402db4aad20STejun Heo } 403db4aad20STejun Heo 404fd7b9f7bSTejun Heo /** 405c637b8acSTejun Heo * kernfs_add_one - add kernfs_node to parent without warning 406324a56e1STejun Heo * @kn: kernfs_node to be added 407fd7b9f7bSTejun Heo * 408db4aad20STejun Heo * The caller must already have initialized @kn->parent. This 409db4aad20STejun Heo * function increments nlink of the parent's inode if @kn is a 410db4aad20STejun Heo * directory and link into the children list of the parent. 411fd7b9f7bSTejun Heo * 412fd7b9f7bSTejun Heo * RETURNS: 413fd7b9f7bSTejun Heo * 0 on success, -EEXIST if entry with the given name already 414fd7b9f7bSTejun Heo * exists. 415fd7b9f7bSTejun Heo */ 416988cd7afSTejun Heo int kernfs_add_one(struct kernfs_node *kn) 417fd7b9f7bSTejun Heo { 418db4aad20STejun Heo struct kernfs_node *parent = kn->parent; 419c525aaddSTejun Heo struct kernfs_iattrs *ps_iattr; 420988cd7afSTejun Heo bool has_ns; 421fd7b9f7bSTejun Heo int ret; 422fd7b9f7bSTejun Heo 423988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 424988cd7afSTejun Heo 425988cd7afSTejun Heo ret = -EINVAL; 426988cd7afSTejun Heo has_ns = kernfs_ns_enabled(parent); 427988cd7afSTejun Heo if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 428988cd7afSTejun Heo has_ns ? "required" : "invalid", parent->name, kn->name)) 429988cd7afSTejun Heo goto out_unlock; 430fd7b9f7bSTejun Heo 431df23fc39STejun Heo if (kernfs_type(parent) != KERNFS_DIR) 432988cd7afSTejun Heo goto out_unlock; 433fd7b9f7bSTejun Heo 434988cd7afSTejun Heo ret = -ENOENT; 435798c75a0SGreg Kroah-Hartman if (parent->flags & KERNFS_REMOVED) 436988cd7afSTejun Heo goto out_unlock; 437798c75a0SGreg Kroah-Hartman 438c637b8acSTejun Heo kn->hash = kernfs_name_hash(kn->name, kn->ns); 439fd7b9f7bSTejun Heo 440c637b8acSTejun Heo ret = kernfs_link_sibling(kn); 441fd7b9f7bSTejun Heo if (ret) 442988cd7afSTejun Heo goto out_unlock; 443fd7b9f7bSTejun Heo 444fd7b9f7bSTejun Heo /* Update timestamps on the parent */ 445adc5e8b5STejun Heo ps_iattr = parent->iattr; 446fd7b9f7bSTejun Heo if (ps_iattr) { 447fd7b9f7bSTejun Heo struct iattr *ps_iattrs = &ps_iattr->ia_iattr; 448fd7b9f7bSTejun Heo ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; 449fd7b9f7bSTejun Heo } 450fd7b9f7bSTejun Heo 451fd7b9f7bSTejun Heo /* Mark the entry added into directory tree */ 452798c75a0SGreg Kroah-Hartman kn->flags &= ~KERNFS_REMOVED; 453988cd7afSTejun Heo ret = 0; 454988cd7afSTejun Heo out_unlock: 455a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 456988cd7afSTejun Heo return ret; 457fd7b9f7bSTejun Heo } 458fd7b9f7bSTejun Heo 459fd7b9f7bSTejun Heo /** 460324a56e1STejun Heo * kernfs_find_ns - find kernfs_node with the given name 461324a56e1STejun Heo * @parent: kernfs_node to search under 462fd7b9f7bSTejun Heo * @name: name to look for 463fd7b9f7bSTejun Heo * @ns: the namespace tag to use 464fd7b9f7bSTejun Heo * 465324a56e1STejun Heo * Look for kernfs_node with name @name under @parent. Returns pointer to 466324a56e1STejun Heo * the found kernfs_node on success, %NULL on failure. 467fd7b9f7bSTejun Heo */ 468324a56e1STejun Heo static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, 469fd7b9f7bSTejun Heo const unsigned char *name, 470fd7b9f7bSTejun Heo const void *ns) 471fd7b9f7bSTejun Heo { 472adc5e8b5STejun Heo struct rb_node *node = parent->dir.children.rb_node; 473ac9bba03STejun Heo bool has_ns = kernfs_ns_enabled(parent); 474fd7b9f7bSTejun Heo unsigned int hash; 475fd7b9f7bSTejun Heo 476a797bfc3STejun Heo lockdep_assert_held(&kernfs_mutex); 477fd7b9f7bSTejun Heo 478fd7b9f7bSTejun Heo if (has_ns != (bool)ns) { 479c637b8acSTejun Heo WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 480adc5e8b5STejun Heo has_ns ? "required" : "invalid", parent->name, name); 481fd7b9f7bSTejun Heo return NULL; 482fd7b9f7bSTejun Heo } 483fd7b9f7bSTejun Heo 484c637b8acSTejun Heo hash = kernfs_name_hash(name, ns); 485fd7b9f7bSTejun Heo while (node) { 486324a56e1STejun Heo struct kernfs_node *kn; 487fd7b9f7bSTejun Heo int result; 488fd7b9f7bSTejun Heo 489324a56e1STejun Heo kn = rb_to_kn(node); 490c637b8acSTejun Heo result = kernfs_name_compare(hash, name, ns, kn); 491fd7b9f7bSTejun Heo if (result < 0) 492fd7b9f7bSTejun Heo node = node->rb_left; 493fd7b9f7bSTejun Heo else if (result > 0) 494fd7b9f7bSTejun Heo node = node->rb_right; 495fd7b9f7bSTejun Heo else 496324a56e1STejun Heo return kn; 497fd7b9f7bSTejun Heo } 498fd7b9f7bSTejun Heo return NULL; 499fd7b9f7bSTejun Heo } 500fd7b9f7bSTejun Heo 501fd7b9f7bSTejun Heo /** 502324a56e1STejun Heo * kernfs_find_and_get_ns - find and get kernfs_node with the given name 503324a56e1STejun Heo * @parent: kernfs_node to search under 504fd7b9f7bSTejun Heo * @name: name to look for 505fd7b9f7bSTejun Heo * @ns: the namespace tag to use 506fd7b9f7bSTejun Heo * 507324a56e1STejun Heo * Look for kernfs_node with name @name under @parent and get a reference 508fd7b9f7bSTejun Heo * if found. This function may sleep and returns pointer to the found 509324a56e1STejun Heo * kernfs_node on success, %NULL on failure. 510fd7b9f7bSTejun Heo */ 511324a56e1STejun Heo struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, 512fd7b9f7bSTejun Heo const char *name, const void *ns) 513fd7b9f7bSTejun Heo { 514324a56e1STejun Heo struct kernfs_node *kn; 515fd7b9f7bSTejun Heo 516a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 517324a56e1STejun Heo kn = kernfs_find_ns(parent, name, ns); 518324a56e1STejun Heo kernfs_get(kn); 519a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 520fd7b9f7bSTejun Heo 521324a56e1STejun Heo return kn; 522fd7b9f7bSTejun Heo } 523fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); 524fd7b9f7bSTejun Heo 525fd7b9f7bSTejun Heo /** 526ba7443bcSTejun Heo * kernfs_create_root - create a new kernfs hierarchy 52780b9bbefSTejun Heo * @kdops: optional directory syscall operations for the hierarchy 528ba7443bcSTejun Heo * @priv: opaque data associated with the new directory 529ba7443bcSTejun Heo * 530ba7443bcSTejun Heo * Returns the root of the new hierarchy on success, ERR_PTR() value on 531ba7443bcSTejun Heo * failure. 532ba7443bcSTejun Heo */ 53380b9bbefSTejun Heo struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv) 534ba7443bcSTejun Heo { 535ba7443bcSTejun Heo struct kernfs_root *root; 536324a56e1STejun Heo struct kernfs_node *kn; 537ba7443bcSTejun Heo 538ba7443bcSTejun Heo root = kzalloc(sizeof(*root), GFP_KERNEL); 539ba7443bcSTejun Heo if (!root) 540ba7443bcSTejun Heo return ERR_PTR(-ENOMEM); 541ba7443bcSTejun Heo 542bc755553STejun Heo ida_init(&root->ino_ida); 543bc755553STejun Heo 544db4aad20STejun Heo kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, 545db4aad20STejun Heo KERNFS_DIR); 546324a56e1STejun Heo if (!kn) { 547bc755553STejun Heo ida_destroy(&root->ino_ida); 548ba7443bcSTejun Heo kfree(root); 549ba7443bcSTejun Heo return ERR_PTR(-ENOMEM); 550ba7443bcSTejun Heo } 551ba7443bcSTejun Heo 552798c75a0SGreg Kroah-Hartman kn->flags &= ~KERNFS_REMOVED; 553324a56e1STejun Heo kn->priv = priv; 554adc5e8b5STejun Heo kn->dir.root = root; 555ba7443bcSTejun Heo 55680b9bbefSTejun Heo root->dir_ops = kdops; 557324a56e1STejun Heo root->kn = kn; 558abd54f02STejun Heo init_waitqueue_head(&root->deactivate_waitq); 559ba7443bcSTejun Heo 560ba7443bcSTejun Heo return root; 561ba7443bcSTejun Heo } 562ba7443bcSTejun Heo 563ba7443bcSTejun Heo /** 564ba7443bcSTejun Heo * kernfs_destroy_root - destroy a kernfs hierarchy 565ba7443bcSTejun Heo * @root: root of the hierarchy to destroy 566ba7443bcSTejun Heo * 567ba7443bcSTejun Heo * Destroy the hierarchy anchored at @root by removing all existing 568ba7443bcSTejun Heo * directories and destroying @root. 569ba7443bcSTejun Heo */ 570ba7443bcSTejun Heo void kernfs_destroy_root(struct kernfs_root *root) 571ba7443bcSTejun Heo { 572324a56e1STejun Heo kernfs_remove(root->kn); /* will also free @root */ 573ba7443bcSTejun Heo } 574ba7443bcSTejun Heo 575ba7443bcSTejun Heo /** 576fd7b9f7bSTejun Heo * kernfs_create_dir_ns - create a directory 577fd7b9f7bSTejun Heo * @parent: parent in which to create a new directory 578fd7b9f7bSTejun Heo * @name: name of the new directory 579bb8b9d09STejun Heo * @mode: mode of the new directory 580fd7b9f7bSTejun Heo * @priv: opaque data associated with the new directory 581fd7b9f7bSTejun Heo * @ns: optional namespace tag of the directory 582fd7b9f7bSTejun Heo * 583fd7b9f7bSTejun Heo * Returns the created node on success, ERR_PTR() value on failure. 584fd7b9f7bSTejun Heo */ 585324a56e1STejun Heo struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, 586bb8b9d09STejun Heo const char *name, umode_t mode, 587bb8b9d09STejun Heo void *priv, const void *ns) 588fd7b9f7bSTejun Heo { 589324a56e1STejun Heo struct kernfs_node *kn; 590fd7b9f7bSTejun Heo int rc; 591fd7b9f7bSTejun Heo 592fd7b9f7bSTejun Heo /* allocate */ 593db4aad20STejun Heo kn = kernfs_new_node(parent, name, mode | S_IFDIR, KERNFS_DIR); 594324a56e1STejun Heo if (!kn) 595fd7b9f7bSTejun Heo return ERR_PTR(-ENOMEM); 596fd7b9f7bSTejun Heo 597adc5e8b5STejun Heo kn->dir.root = parent->dir.root; 598adc5e8b5STejun Heo kn->ns = ns; 599324a56e1STejun Heo kn->priv = priv; 600fd7b9f7bSTejun Heo 601fd7b9f7bSTejun Heo /* link in */ 602988cd7afSTejun Heo rc = kernfs_add_one(kn); 603fd7b9f7bSTejun Heo if (!rc) 604324a56e1STejun Heo return kn; 605fd7b9f7bSTejun Heo 606324a56e1STejun Heo kernfs_put(kn); 607fd7b9f7bSTejun Heo return ERR_PTR(rc); 608fd7b9f7bSTejun Heo } 609fd7b9f7bSTejun Heo 610c637b8acSTejun Heo static struct dentry *kernfs_iop_lookup(struct inode *dir, 611c637b8acSTejun Heo struct dentry *dentry, 612fd7b9f7bSTejun Heo unsigned int flags) 613fd7b9f7bSTejun Heo { 61419bbb926STejun Heo struct dentry *ret; 615324a56e1STejun Heo struct kernfs_node *parent = dentry->d_parent->d_fsdata; 616324a56e1STejun Heo struct kernfs_node *kn; 617fd7b9f7bSTejun Heo struct inode *inode; 618fd7b9f7bSTejun Heo const void *ns = NULL; 619fd7b9f7bSTejun Heo 620a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 621fd7b9f7bSTejun Heo 622324a56e1STejun Heo if (kernfs_ns_enabled(parent)) 623c525aaddSTejun Heo ns = kernfs_info(dir->i_sb)->ns; 624fd7b9f7bSTejun Heo 625324a56e1STejun Heo kn = kernfs_find_ns(parent, dentry->d_name.name, ns); 626fd7b9f7bSTejun Heo 627fd7b9f7bSTejun Heo /* no such entry */ 628324a56e1STejun Heo if (!kn) { 62919bbb926STejun Heo ret = NULL; 630fd7b9f7bSTejun Heo goto out_unlock; 631fd7b9f7bSTejun Heo } 632324a56e1STejun Heo kernfs_get(kn); 633324a56e1STejun Heo dentry->d_fsdata = kn; 634fd7b9f7bSTejun Heo 635fd7b9f7bSTejun Heo /* attach dentry and inode */ 636c637b8acSTejun Heo inode = kernfs_get_inode(dir->i_sb, kn); 637fd7b9f7bSTejun Heo if (!inode) { 638fd7b9f7bSTejun Heo ret = ERR_PTR(-ENOMEM); 639fd7b9f7bSTejun Heo goto out_unlock; 640fd7b9f7bSTejun Heo } 641fd7b9f7bSTejun Heo 642fd7b9f7bSTejun Heo /* instantiate and hash dentry */ 643fd7b9f7bSTejun Heo ret = d_materialise_unique(dentry, inode); 644fd7b9f7bSTejun Heo out_unlock: 645a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 646fd7b9f7bSTejun Heo return ret; 647fd7b9f7bSTejun Heo } 648fd7b9f7bSTejun Heo 64980b9bbefSTejun Heo static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry, 65080b9bbefSTejun Heo umode_t mode) 65180b9bbefSTejun Heo { 65280b9bbefSTejun Heo struct kernfs_node *parent = dir->i_private; 65380b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops; 65480b9bbefSTejun Heo 65580b9bbefSTejun Heo if (!kdops || !kdops->mkdir) 65680b9bbefSTejun Heo return -EPERM; 65780b9bbefSTejun Heo 65880b9bbefSTejun Heo return kdops->mkdir(parent, dentry->d_name.name, mode); 65980b9bbefSTejun Heo } 66080b9bbefSTejun Heo 66180b9bbefSTejun Heo static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) 66280b9bbefSTejun Heo { 66380b9bbefSTejun Heo struct kernfs_node *kn = dentry->d_fsdata; 66480b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops; 66580b9bbefSTejun Heo 66680b9bbefSTejun Heo if (!kdops || !kdops->rmdir) 66780b9bbefSTejun Heo return -EPERM; 66880b9bbefSTejun Heo 66980b9bbefSTejun Heo return kdops->rmdir(kn); 67080b9bbefSTejun Heo } 67180b9bbefSTejun Heo 67280b9bbefSTejun Heo static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry, 67380b9bbefSTejun Heo struct inode *new_dir, struct dentry *new_dentry) 67480b9bbefSTejun Heo { 67580b9bbefSTejun Heo struct kernfs_node *kn = old_dentry->d_fsdata; 67680b9bbefSTejun Heo struct kernfs_node *new_parent = new_dir->i_private; 67780b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops; 67880b9bbefSTejun Heo 67980b9bbefSTejun Heo if (!kdops || !kdops->rename) 68080b9bbefSTejun Heo return -EPERM; 68180b9bbefSTejun Heo 68280b9bbefSTejun Heo return kdops->rename(kn, new_parent, new_dentry->d_name.name); 68380b9bbefSTejun Heo } 68480b9bbefSTejun Heo 685a797bfc3STejun Heo const struct inode_operations kernfs_dir_iops = { 686c637b8acSTejun Heo .lookup = kernfs_iop_lookup, 687c637b8acSTejun Heo .permission = kernfs_iop_permission, 688c637b8acSTejun Heo .setattr = kernfs_iop_setattr, 689c637b8acSTejun Heo .getattr = kernfs_iop_getattr, 690c637b8acSTejun Heo .setxattr = kernfs_iop_setxattr, 691c637b8acSTejun Heo .removexattr = kernfs_iop_removexattr, 692c637b8acSTejun Heo .getxattr = kernfs_iop_getxattr, 693c637b8acSTejun Heo .listxattr = kernfs_iop_listxattr, 69480b9bbefSTejun Heo 69580b9bbefSTejun Heo .mkdir = kernfs_iop_mkdir, 69680b9bbefSTejun Heo .rmdir = kernfs_iop_rmdir, 69780b9bbefSTejun Heo .rename = kernfs_iop_rename, 698fd7b9f7bSTejun Heo }; 699fd7b9f7bSTejun Heo 700c637b8acSTejun Heo static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos) 701fd7b9f7bSTejun Heo { 702324a56e1STejun Heo struct kernfs_node *last; 703fd7b9f7bSTejun Heo 704fd7b9f7bSTejun Heo while (true) { 705fd7b9f7bSTejun Heo struct rb_node *rbn; 706fd7b9f7bSTejun Heo 707fd7b9f7bSTejun Heo last = pos; 708fd7b9f7bSTejun Heo 709df23fc39STejun Heo if (kernfs_type(pos) != KERNFS_DIR) 710fd7b9f7bSTejun Heo break; 711fd7b9f7bSTejun Heo 712adc5e8b5STejun Heo rbn = rb_first(&pos->dir.children); 713fd7b9f7bSTejun Heo if (!rbn) 714fd7b9f7bSTejun Heo break; 715fd7b9f7bSTejun Heo 716324a56e1STejun Heo pos = rb_to_kn(rbn); 717fd7b9f7bSTejun Heo } 718fd7b9f7bSTejun Heo 719fd7b9f7bSTejun Heo return last; 720fd7b9f7bSTejun Heo } 721fd7b9f7bSTejun Heo 722fd7b9f7bSTejun Heo /** 723c637b8acSTejun Heo * kernfs_next_descendant_post - find the next descendant for post-order walk 724fd7b9f7bSTejun Heo * @pos: the current position (%NULL to initiate traversal) 725324a56e1STejun Heo * @root: kernfs_node whose descendants to walk 726fd7b9f7bSTejun Heo * 727fd7b9f7bSTejun Heo * Find the next descendant to visit for post-order traversal of @root's 728fd7b9f7bSTejun Heo * descendants. @root is included in the iteration and the last node to be 729fd7b9f7bSTejun Heo * visited. 730fd7b9f7bSTejun Heo */ 731c637b8acSTejun Heo static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, 732324a56e1STejun Heo struct kernfs_node *root) 733fd7b9f7bSTejun Heo { 734fd7b9f7bSTejun Heo struct rb_node *rbn; 735fd7b9f7bSTejun Heo 736a797bfc3STejun Heo lockdep_assert_held(&kernfs_mutex); 737fd7b9f7bSTejun Heo 738fd7b9f7bSTejun Heo /* if first iteration, visit leftmost descendant which may be root */ 739fd7b9f7bSTejun Heo if (!pos) 740c637b8acSTejun Heo return kernfs_leftmost_descendant(root); 741fd7b9f7bSTejun Heo 742fd7b9f7bSTejun Heo /* if we visited @root, we're done */ 743fd7b9f7bSTejun Heo if (pos == root) 744fd7b9f7bSTejun Heo return NULL; 745fd7b9f7bSTejun Heo 746fd7b9f7bSTejun Heo /* if there's an unvisited sibling, visit its leftmost descendant */ 747adc5e8b5STejun Heo rbn = rb_next(&pos->rb); 748fd7b9f7bSTejun Heo if (rbn) 749c637b8acSTejun Heo return kernfs_leftmost_descendant(rb_to_kn(rbn)); 750fd7b9f7bSTejun Heo 751fd7b9f7bSTejun Heo /* no sibling left, visit parent */ 752adc5e8b5STejun Heo return pos->parent; 753fd7b9f7bSTejun Heo } 754fd7b9f7bSTejun Heo 755988cd7afSTejun Heo static void __kernfs_remove(struct kernfs_node *kn) 756fd7b9f7bSTejun Heo { 75735beab06STejun Heo struct kernfs_node *pos; 75835beab06STejun Heo 75935beab06STejun Heo lockdep_assert_held(&kernfs_mutex); 760fd7b9f7bSTejun Heo 761ce9b499cSGreg Kroah-Hartman if (!kn) 762ce9b499cSGreg Kroah-Hartman return; 763ce9b499cSGreg Kroah-Hartman 764c637b8acSTejun Heo pr_debug("kernfs %s: removing\n", kn->name); 765fd7b9f7bSTejun Heo 76635beab06STejun Heo /* disable lookup and node creation under @kn */ 76735beab06STejun Heo pos = NULL; 76835beab06STejun Heo while ((pos = kernfs_next_descendant_post(pos, kn))) 76935beab06STejun Heo pos->flags |= KERNFS_REMOVED; 77035beab06STejun Heo 77135beab06STejun Heo /* deactivate and unlink the subtree node-by-node */ 772fd7b9f7bSTejun Heo do { 77335beab06STejun Heo pos = kernfs_leftmost_descendant(kn); 77435beab06STejun Heo 77535beab06STejun Heo /* 77635beab06STejun Heo * kernfs_deactivate() drops kernfs_mutex temporarily and 77735beab06STejun Heo * @pos's base ref could have been put by someone else by 77835beab06STejun Heo * the time the function returns. Make sure it doesn't go 77935beab06STejun Heo * away underneath us. 78035beab06STejun Heo */ 78135beab06STejun Heo kernfs_get(pos); 78235beab06STejun Heo 78335beab06STejun Heo kernfs_deactivate(pos); 78435beab06STejun Heo 78535beab06STejun Heo /* 78635beab06STejun Heo * kernfs_unlink_sibling() succeeds once per node. Use it 78735beab06STejun Heo * to decide who's responsible for cleanups. 78835beab06STejun Heo */ 78935beab06STejun Heo if (!pos->parent || kernfs_unlink_sibling(pos)) { 79035beab06STejun Heo struct kernfs_iattrs *ps_iattr = 79135beab06STejun Heo pos->parent ? pos->parent->iattr : NULL; 79235beab06STejun Heo 79335beab06STejun Heo /* update timestamps on the parent */ 79435beab06STejun Heo if (ps_iattr) { 79535beab06STejun Heo ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME; 79635beab06STejun Heo ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME; 79735beab06STejun Heo } 79835beab06STejun Heo 799988cd7afSTejun Heo kernfs_put(pos); 80035beab06STejun Heo } 80135beab06STejun Heo 80235beab06STejun Heo kernfs_put(pos); 80335beab06STejun Heo } while (pos != kn); 804fd7b9f7bSTejun Heo } 805fd7b9f7bSTejun Heo 806fd7b9f7bSTejun Heo /** 807324a56e1STejun Heo * kernfs_remove - remove a kernfs_node recursively 808324a56e1STejun Heo * @kn: the kernfs_node to remove 809fd7b9f7bSTejun Heo * 810324a56e1STejun Heo * Remove @kn along with all its subdirectories and files. 811fd7b9f7bSTejun Heo */ 812324a56e1STejun Heo void kernfs_remove(struct kernfs_node *kn) 813fd7b9f7bSTejun Heo { 814988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 815988cd7afSTejun Heo __kernfs_remove(kn); 816988cd7afSTejun Heo mutex_unlock(&kernfs_mutex); 817fd7b9f7bSTejun Heo } 818fd7b9f7bSTejun Heo 819fd7b9f7bSTejun Heo /** 820324a56e1STejun Heo * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it 821324a56e1STejun Heo * @parent: parent of the target 822324a56e1STejun Heo * @name: name of the kernfs_node to remove 823324a56e1STejun Heo * @ns: namespace tag of the kernfs_node to remove 824fd7b9f7bSTejun Heo * 825324a56e1STejun Heo * Look for the kernfs_node with @name and @ns under @parent and remove it. 826324a56e1STejun Heo * Returns 0 on success, -ENOENT if such entry doesn't exist. 827fd7b9f7bSTejun Heo */ 828324a56e1STejun Heo int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, 829fd7b9f7bSTejun Heo const void *ns) 830fd7b9f7bSTejun Heo { 831324a56e1STejun Heo struct kernfs_node *kn; 832fd7b9f7bSTejun Heo 833324a56e1STejun Heo if (!parent) { 834c637b8acSTejun Heo WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n", 835fd7b9f7bSTejun Heo name); 836fd7b9f7bSTejun Heo return -ENOENT; 837fd7b9f7bSTejun Heo } 838fd7b9f7bSTejun Heo 839988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 840fd7b9f7bSTejun Heo 841324a56e1STejun Heo kn = kernfs_find_ns(parent, name, ns); 842324a56e1STejun Heo if (kn) 843988cd7afSTejun Heo __kernfs_remove(kn); 844fd7b9f7bSTejun Heo 845988cd7afSTejun Heo mutex_unlock(&kernfs_mutex); 846fd7b9f7bSTejun Heo 847324a56e1STejun Heo if (kn) 848fd7b9f7bSTejun Heo return 0; 849fd7b9f7bSTejun Heo else 850fd7b9f7bSTejun Heo return -ENOENT; 851fd7b9f7bSTejun Heo } 852fd7b9f7bSTejun Heo 853fd7b9f7bSTejun Heo /** 854fd7b9f7bSTejun Heo * kernfs_rename_ns - move and rename a kernfs_node 855324a56e1STejun Heo * @kn: target node 856fd7b9f7bSTejun Heo * @new_parent: new parent to put @sd under 857fd7b9f7bSTejun Heo * @new_name: new name 858fd7b9f7bSTejun Heo * @new_ns: new namespace tag 859fd7b9f7bSTejun Heo */ 860324a56e1STejun Heo int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, 861fd7b9f7bSTejun Heo const char *new_name, const void *new_ns) 862fd7b9f7bSTejun Heo { 863fd7b9f7bSTejun Heo int error; 864fd7b9f7bSTejun Heo 865ae34372eSTejun Heo mutex_lock(&kernfs_mutex); 866d0ae3d43STejun Heo 867798c75a0SGreg Kroah-Hartman error = -ENOENT; 868798c75a0SGreg Kroah-Hartman if ((kn->flags | new_parent->flags) & KERNFS_REMOVED) 869798c75a0SGreg Kroah-Hartman goto out; 870798c75a0SGreg Kroah-Hartman 871fd7b9f7bSTejun Heo error = 0; 872adc5e8b5STejun Heo if ((kn->parent == new_parent) && (kn->ns == new_ns) && 873adc5e8b5STejun Heo (strcmp(kn->name, new_name) == 0)) 874798c75a0SGreg Kroah-Hartman goto out; /* nothing to rename */ 875fd7b9f7bSTejun Heo 876fd7b9f7bSTejun Heo error = -EEXIST; 877fd7b9f7bSTejun Heo if (kernfs_find_ns(new_parent, new_name, new_ns)) 878798c75a0SGreg Kroah-Hartman goto out; 879fd7b9f7bSTejun Heo 880324a56e1STejun Heo /* rename kernfs_node */ 881adc5e8b5STejun Heo if (strcmp(kn->name, new_name) != 0) { 882fd7b9f7bSTejun Heo error = -ENOMEM; 883fd7b9f7bSTejun Heo new_name = kstrdup(new_name, GFP_KERNEL); 884fd7b9f7bSTejun Heo if (!new_name) 885798c75a0SGreg Kroah-Hartman goto out; 886fd7b9f7bSTejun Heo 88747a52e91STejun Heo if (kn->flags & KERNFS_STATIC_NAME) 88847a52e91STejun Heo kn->flags &= ~KERNFS_STATIC_NAME; 88947a52e91STejun Heo else 890adc5e8b5STejun Heo kfree(kn->name); 89147a52e91STejun Heo 892adc5e8b5STejun Heo kn->name = new_name; 893fd7b9f7bSTejun Heo } 894fd7b9f7bSTejun Heo 895fd7b9f7bSTejun Heo /* 896fd7b9f7bSTejun Heo * Move to the appropriate place in the appropriate directories rbtree. 897fd7b9f7bSTejun Heo */ 898c637b8acSTejun Heo kernfs_unlink_sibling(kn); 899fd7b9f7bSTejun Heo kernfs_get(new_parent); 900adc5e8b5STejun Heo kernfs_put(kn->parent); 901adc5e8b5STejun Heo kn->ns = new_ns; 902c637b8acSTejun Heo kn->hash = kernfs_name_hash(kn->name, kn->ns); 903adc5e8b5STejun Heo kn->parent = new_parent; 904c637b8acSTejun Heo kernfs_link_sibling(kn); 905fd7b9f7bSTejun Heo 906fd7b9f7bSTejun Heo error = 0; 907ae34372eSTejun Heo out: 908798c75a0SGreg Kroah-Hartman mutex_unlock(&kernfs_mutex); 909fd7b9f7bSTejun Heo return error; 910fd7b9f7bSTejun Heo } 911fd7b9f7bSTejun Heo 912fd7b9f7bSTejun Heo /* Relationship between s_mode and the DT_xxx types */ 913324a56e1STejun Heo static inline unsigned char dt_type(struct kernfs_node *kn) 914fd7b9f7bSTejun Heo { 915adc5e8b5STejun Heo return (kn->mode >> 12) & 15; 916fd7b9f7bSTejun Heo } 917fd7b9f7bSTejun Heo 918c637b8acSTejun Heo static int kernfs_dir_fop_release(struct inode *inode, struct file *filp) 919fd7b9f7bSTejun Heo { 920fd7b9f7bSTejun Heo kernfs_put(filp->private_data); 921fd7b9f7bSTejun Heo return 0; 922fd7b9f7bSTejun Heo } 923fd7b9f7bSTejun Heo 924c637b8acSTejun Heo static struct kernfs_node *kernfs_dir_pos(const void *ns, 925324a56e1STejun Heo struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) 926fd7b9f7bSTejun Heo { 927fd7b9f7bSTejun Heo if (pos) { 928798c75a0SGreg Kroah-Hartman int valid = !(pos->flags & KERNFS_REMOVED) && 929798c75a0SGreg Kroah-Hartman pos->parent == parent && hash == pos->hash; 930fd7b9f7bSTejun Heo kernfs_put(pos); 931fd7b9f7bSTejun Heo if (!valid) 932fd7b9f7bSTejun Heo pos = NULL; 933fd7b9f7bSTejun Heo } 934fd7b9f7bSTejun Heo if (!pos && (hash > 1) && (hash < INT_MAX)) { 935adc5e8b5STejun Heo struct rb_node *node = parent->dir.children.rb_node; 936fd7b9f7bSTejun Heo while (node) { 937324a56e1STejun Heo pos = rb_to_kn(node); 938fd7b9f7bSTejun Heo 939adc5e8b5STejun Heo if (hash < pos->hash) 940fd7b9f7bSTejun Heo node = node->rb_left; 941adc5e8b5STejun Heo else if (hash > pos->hash) 942fd7b9f7bSTejun Heo node = node->rb_right; 943fd7b9f7bSTejun Heo else 944fd7b9f7bSTejun Heo break; 945fd7b9f7bSTejun Heo } 946fd7b9f7bSTejun Heo } 947fd7b9f7bSTejun Heo /* Skip over entries in the wrong namespace */ 948adc5e8b5STejun Heo while (pos && pos->ns != ns) { 949adc5e8b5STejun Heo struct rb_node *node = rb_next(&pos->rb); 950fd7b9f7bSTejun Heo if (!node) 951fd7b9f7bSTejun Heo pos = NULL; 952fd7b9f7bSTejun Heo else 953324a56e1STejun Heo pos = rb_to_kn(node); 954fd7b9f7bSTejun Heo } 955fd7b9f7bSTejun Heo return pos; 956fd7b9f7bSTejun Heo } 957fd7b9f7bSTejun Heo 958c637b8acSTejun Heo static struct kernfs_node *kernfs_dir_next_pos(const void *ns, 959324a56e1STejun Heo struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos) 960fd7b9f7bSTejun Heo { 961c637b8acSTejun Heo pos = kernfs_dir_pos(ns, parent, ino, pos); 962fd7b9f7bSTejun Heo if (pos) 963fd7b9f7bSTejun Heo do { 964adc5e8b5STejun Heo struct rb_node *node = rb_next(&pos->rb); 965fd7b9f7bSTejun Heo if (!node) 966fd7b9f7bSTejun Heo pos = NULL; 967fd7b9f7bSTejun Heo else 968324a56e1STejun Heo pos = rb_to_kn(node); 969adc5e8b5STejun Heo } while (pos && pos->ns != ns); 970fd7b9f7bSTejun Heo return pos; 971fd7b9f7bSTejun Heo } 972fd7b9f7bSTejun Heo 973c637b8acSTejun Heo static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) 974fd7b9f7bSTejun Heo { 975fd7b9f7bSTejun Heo struct dentry *dentry = file->f_path.dentry; 976324a56e1STejun Heo struct kernfs_node *parent = dentry->d_fsdata; 977324a56e1STejun Heo struct kernfs_node *pos = file->private_data; 978fd7b9f7bSTejun Heo const void *ns = NULL; 979fd7b9f7bSTejun Heo 980fd7b9f7bSTejun Heo if (!dir_emit_dots(file, ctx)) 981fd7b9f7bSTejun Heo return 0; 982a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 983fd7b9f7bSTejun Heo 984324a56e1STejun Heo if (kernfs_ns_enabled(parent)) 985c525aaddSTejun Heo ns = kernfs_info(dentry->d_sb)->ns; 986fd7b9f7bSTejun Heo 987c637b8acSTejun Heo for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos); 988fd7b9f7bSTejun Heo pos; 989c637b8acSTejun Heo pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) { 990adc5e8b5STejun Heo const char *name = pos->name; 991fd7b9f7bSTejun Heo unsigned int type = dt_type(pos); 992fd7b9f7bSTejun Heo int len = strlen(name); 993adc5e8b5STejun Heo ino_t ino = pos->ino; 994fd7b9f7bSTejun Heo 995adc5e8b5STejun Heo ctx->pos = pos->hash; 996fd7b9f7bSTejun Heo file->private_data = pos; 997fd7b9f7bSTejun Heo kernfs_get(pos); 998fd7b9f7bSTejun Heo 999a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 1000fd7b9f7bSTejun Heo if (!dir_emit(ctx, name, len, ino, type)) 1001fd7b9f7bSTejun Heo return 0; 1002a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 1003fd7b9f7bSTejun Heo } 1004a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 1005fd7b9f7bSTejun Heo file->private_data = NULL; 1006fd7b9f7bSTejun Heo ctx->pos = INT_MAX; 1007fd7b9f7bSTejun Heo return 0; 1008fd7b9f7bSTejun Heo } 1009fd7b9f7bSTejun Heo 1010c637b8acSTejun Heo static loff_t kernfs_dir_fop_llseek(struct file *file, loff_t offset, 1011c637b8acSTejun Heo int whence) 1012fd7b9f7bSTejun Heo { 1013fd7b9f7bSTejun Heo struct inode *inode = file_inode(file); 1014fd7b9f7bSTejun Heo loff_t ret; 1015fd7b9f7bSTejun Heo 1016fd7b9f7bSTejun Heo mutex_lock(&inode->i_mutex); 1017fd7b9f7bSTejun Heo ret = generic_file_llseek(file, offset, whence); 1018fd7b9f7bSTejun Heo mutex_unlock(&inode->i_mutex); 1019fd7b9f7bSTejun Heo 1020fd7b9f7bSTejun Heo return ret; 1021fd7b9f7bSTejun Heo } 1022fd7b9f7bSTejun Heo 1023a797bfc3STejun Heo const struct file_operations kernfs_dir_fops = { 1024fd7b9f7bSTejun Heo .read = generic_read_dir, 1025c637b8acSTejun Heo .iterate = kernfs_fop_readdir, 1026c637b8acSTejun Heo .release = kernfs_dir_fop_release, 1027c637b8acSTejun Heo .llseek = kernfs_dir_fop_llseek, 1028fd7b9f7bSTejun Heo }; 1029