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 2581c173cbSTejun Heo static bool kernfs_active(struct kernfs_node *kn) 2681c173cbSTejun Heo { 2781c173cbSTejun Heo lockdep_assert_held(&kernfs_mutex); 2881c173cbSTejun Heo return atomic_read(&kn->active) >= 0; 2981c173cbSTejun Heo } 3081c173cbSTejun Heo 31182fd64bSTejun Heo static bool kernfs_lockdep(struct kernfs_node *kn) 32182fd64bSTejun Heo { 33182fd64bSTejun Heo #ifdef CONFIG_DEBUG_LOCK_ALLOC 34182fd64bSTejun Heo return kn->flags & KERNFS_LOCKDEP; 35182fd64bSTejun Heo #else 36182fd64bSTejun Heo return false; 37182fd64bSTejun Heo #endif 38182fd64bSTejun Heo } 39182fd64bSTejun Heo 40fd7b9f7bSTejun Heo /** 41c637b8acSTejun Heo * kernfs_name_hash 42fd7b9f7bSTejun Heo * @name: Null terminated string to hash 43fd7b9f7bSTejun Heo * @ns: Namespace tag to hash 44fd7b9f7bSTejun Heo * 45fd7b9f7bSTejun Heo * Returns 31 bit hash of ns + name (so it fits in an off_t ) 46fd7b9f7bSTejun Heo */ 47c637b8acSTejun Heo static unsigned int kernfs_name_hash(const char *name, const void *ns) 48fd7b9f7bSTejun Heo { 49fd7b9f7bSTejun Heo unsigned long hash = init_name_hash(); 50fd7b9f7bSTejun Heo unsigned int len = strlen(name); 51fd7b9f7bSTejun Heo while (len--) 52fd7b9f7bSTejun Heo hash = partial_name_hash(*name++, hash); 53fd7b9f7bSTejun Heo hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31)); 54fd7b9f7bSTejun Heo hash &= 0x7fffffffU; 55fd7b9f7bSTejun Heo /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ 56fd7b9f7bSTejun Heo if (hash < 1) 57fd7b9f7bSTejun Heo hash += 2; 58fd7b9f7bSTejun Heo if (hash >= INT_MAX) 59fd7b9f7bSTejun Heo hash = INT_MAX - 1; 60fd7b9f7bSTejun Heo return hash; 61fd7b9f7bSTejun Heo } 62fd7b9f7bSTejun Heo 63c637b8acSTejun Heo static int kernfs_name_compare(unsigned int hash, const char *name, 64324a56e1STejun Heo const void *ns, const struct kernfs_node *kn) 65fd7b9f7bSTejun Heo { 66adc5e8b5STejun Heo if (hash != kn->hash) 67adc5e8b5STejun Heo return hash - kn->hash; 68adc5e8b5STejun Heo if (ns != kn->ns) 69adc5e8b5STejun Heo return ns - kn->ns; 70adc5e8b5STejun Heo return strcmp(name, kn->name); 71fd7b9f7bSTejun Heo } 72fd7b9f7bSTejun Heo 73c637b8acSTejun Heo static int kernfs_sd_compare(const struct kernfs_node *left, 74324a56e1STejun Heo const struct kernfs_node *right) 75fd7b9f7bSTejun Heo { 76c637b8acSTejun Heo return kernfs_name_compare(left->hash, left->name, left->ns, right); 77fd7b9f7bSTejun Heo } 78fd7b9f7bSTejun Heo 79fd7b9f7bSTejun Heo /** 80c637b8acSTejun Heo * kernfs_link_sibling - link kernfs_node into sibling rbtree 81324a56e1STejun Heo * @kn: kernfs_node of interest 82fd7b9f7bSTejun Heo * 83324a56e1STejun Heo * Link @kn into its sibling rbtree which starts from 84adc5e8b5STejun Heo * @kn->parent->dir.children. 85fd7b9f7bSTejun Heo * 86fd7b9f7bSTejun Heo * Locking: 87a797bfc3STejun Heo * mutex_lock(kernfs_mutex) 88fd7b9f7bSTejun Heo * 89fd7b9f7bSTejun Heo * RETURNS: 90fd7b9f7bSTejun Heo * 0 on susccess -EEXIST on failure. 91fd7b9f7bSTejun Heo */ 92c637b8acSTejun Heo static int kernfs_link_sibling(struct kernfs_node *kn) 93fd7b9f7bSTejun Heo { 94adc5e8b5STejun Heo struct rb_node **node = &kn->parent->dir.children.rb_node; 95fd7b9f7bSTejun Heo struct rb_node *parent = NULL; 96fd7b9f7bSTejun Heo 97df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_DIR) 98adc5e8b5STejun Heo kn->parent->dir.subdirs++; 99fd7b9f7bSTejun Heo 100fd7b9f7bSTejun Heo while (*node) { 101324a56e1STejun Heo struct kernfs_node *pos; 102fd7b9f7bSTejun Heo int result; 103fd7b9f7bSTejun Heo 104324a56e1STejun Heo pos = rb_to_kn(*node); 105fd7b9f7bSTejun Heo parent = *node; 106c637b8acSTejun Heo result = kernfs_sd_compare(kn, pos); 107fd7b9f7bSTejun Heo if (result < 0) 108adc5e8b5STejun Heo node = &pos->rb.rb_left; 109fd7b9f7bSTejun Heo else if (result > 0) 110adc5e8b5STejun Heo node = &pos->rb.rb_right; 111fd7b9f7bSTejun Heo else 112fd7b9f7bSTejun Heo return -EEXIST; 113fd7b9f7bSTejun Heo } 114fd7b9f7bSTejun Heo /* add new node and rebalance the tree */ 115adc5e8b5STejun Heo rb_link_node(&kn->rb, parent, node); 116adc5e8b5STejun Heo rb_insert_color(&kn->rb, &kn->parent->dir.children); 117fd7b9f7bSTejun Heo return 0; 118fd7b9f7bSTejun Heo } 119fd7b9f7bSTejun Heo 120fd7b9f7bSTejun Heo /** 121c637b8acSTejun Heo * kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree 122324a56e1STejun Heo * @kn: kernfs_node of interest 123fd7b9f7bSTejun Heo * 12435beab06STejun Heo * Try to unlink @kn from its sibling rbtree which starts from 12535beab06STejun Heo * kn->parent->dir.children. Returns %true if @kn was actually 12635beab06STejun Heo * removed, %false if @kn wasn't on the rbtree. 127fd7b9f7bSTejun Heo * 128fd7b9f7bSTejun Heo * Locking: 129a797bfc3STejun Heo * mutex_lock(kernfs_mutex) 130fd7b9f7bSTejun Heo */ 13135beab06STejun Heo static bool kernfs_unlink_sibling(struct kernfs_node *kn) 132fd7b9f7bSTejun Heo { 13335beab06STejun Heo if (RB_EMPTY_NODE(&kn->rb)) 13435beab06STejun Heo return false; 13535beab06STejun Heo 136df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_DIR) 137adc5e8b5STejun Heo kn->parent->dir.subdirs--; 138fd7b9f7bSTejun Heo 139adc5e8b5STejun Heo rb_erase(&kn->rb, &kn->parent->dir.children); 14035beab06STejun Heo RB_CLEAR_NODE(&kn->rb); 14135beab06STejun Heo return true; 142fd7b9f7bSTejun Heo } 143fd7b9f7bSTejun Heo 144fd7b9f7bSTejun Heo /** 145c637b8acSTejun Heo * kernfs_get_active - get an active reference to kernfs_node 146324a56e1STejun Heo * @kn: kernfs_node to get an active reference to 147fd7b9f7bSTejun Heo * 148324a56e1STejun Heo * Get an active reference of @kn. This function is noop if @kn 149fd7b9f7bSTejun Heo * is NULL. 150fd7b9f7bSTejun Heo * 151fd7b9f7bSTejun Heo * RETURNS: 152324a56e1STejun Heo * Pointer to @kn on success, NULL on failure. 153fd7b9f7bSTejun Heo */ 154c637b8acSTejun Heo struct kernfs_node *kernfs_get_active(struct kernfs_node *kn) 155fd7b9f7bSTejun Heo { 156324a56e1STejun Heo if (unlikely(!kn)) 157fd7b9f7bSTejun Heo return NULL; 158fd7b9f7bSTejun Heo 159f4b3e631SGreg Kroah-Hartman if (!atomic_inc_unless_negative(&kn->active)) 160f4b3e631SGreg Kroah-Hartman return NULL; 161f4b3e631SGreg Kroah-Hartman 162182fd64bSTejun Heo if (kernfs_lockdep(kn)) 163324a56e1STejun Heo rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); 164324a56e1STejun Heo return kn; 165fd7b9f7bSTejun Heo } 166fd7b9f7bSTejun Heo 167fd7b9f7bSTejun Heo /** 168c637b8acSTejun Heo * kernfs_put_active - put an active reference to kernfs_node 169324a56e1STejun Heo * @kn: kernfs_node to put an active reference to 170fd7b9f7bSTejun Heo * 171324a56e1STejun Heo * Put an active reference to @kn. This function is noop if @kn 172fd7b9f7bSTejun Heo * is NULL. 173fd7b9f7bSTejun Heo */ 174c637b8acSTejun Heo void kernfs_put_active(struct kernfs_node *kn) 175fd7b9f7bSTejun Heo { 176abd54f02STejun Heo struct kernfs_root *root = kernfs_root(kn); 177fd7b9f7bSTejun Heo int v; 178fd7b9f7bSTejun Heo 179324a56e1STejun Heo if (unlikely(!kn)) 180fd7b9f7bSTejun Heo return; 181fd7b9f7bSTejun Heo 182182fd64bSTejun Heo if (kernfs_lockdep(kn)) 183324a56e1STejun Heo rwsem_release(&kn->dep_map, 1, _RET_IP_); 184adc5e8b5STejun Heo v = atomic_dec_return(&kn->active); 185df23fc39STejun Heo if (likely(v != KN_DEACTIVATED_BIAS)) 186fd7b9f7bSTejun Heo return; 187fd7b9f7bSTejun Heo 188abd54f02STejun Heo wake_up_all(&root->deactivate_waitq); 189fd7b9f7bSTejun Heo } 190fd7b9f7bSTejun Heo 191fd7b9f7bSTejun Heo /** 19281c173cbSTejun Heo * kernfs_drain - drain kernfs_node 19381c173cbSTejun Heo * @kn: kernfs_node to drain 194fd7b9f7bSTejun Heo * 19581c173cbSTejun Heo * Drain existing usages and nuke all existing mmaps of @kn. Mutiple 19681c173cbSTejun Heo * removers may invoke this function concurrently on @kn and all will 19781c173cbSTejun Heo * return after draining is complete. 198fd7b9f7bSTejun Heo */ 19981c173cbSTejun Heo static void kernfs_drain(struct kernfs_node *kn) 20035beab06STejun Heo __releases(&kernfs_mutex) __acquires(&kernfs_mutex) 201fd7b9f7bSTejun Heo { 202abd54f02STejun Heo struct kernfs_root *root = kernfs_root(kn); 203fd7b9f7bSTejun Heo 20435beab06STejun Heo lockdep_assert_held(&kernfs_mutex); 20581c173cbSTejun Heo WARN_ON_ONCE(kernfs_active(kn)); 206abd54f02STejun Heo 20735beab06STejun Heo mutex_unlock(&kernfs_mutex); 208abd54f02STejun Heo 209182fd64bSTejun Heo if (kernfs_lockdep(kn)) { 21035beab06STejun Heo rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); 21135beab06STejun Heo if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) 21235beab06STejun Heo lock_contended(&kn->dep_map, _RET_IP_); 21335beab06STejun Heo } 21435beab06STejun Heo 21535beab06STejun Heo /* but everyone should wait for draining */ 216abd54f02STejun Heo wait_event(root->deactivate_waitq, 217abd54f02STejun Heo atomic_read(&kn->active) == KN_DEACTIVATED_BIAS); 218fd7b9f7bSTejun Heo 219182fd64bSTejun Heo if (kernfs_lockdep(kn)) { 220324a56e1STejun Heo lock_acquired(&kn->dep_map, _RET_IP_); 221324a56e1STejun Heo rwsem_release(&kn->dep_map, 1, _RET_IP_); 222fd7b9f7bSTejun Heo } 22335beab06STejun Heo 224ccf02aafSTejun Heo kernfs_unmap_bin_file(kn); 225ccf02aafSTejun Heo 22635beab06STejun Heo mutex_lock(&kernfs_mutex); 227a6607930STejun Heo } 228fd7b9f7bSTejun Heo 229fd7b9f7bSTejun Heo /** 230324a56e1STejun Heo * kernfs_get - get a reference count on a kernfs_node 231324a56e1STejun Heo * @kn: the target kernfs_node 232fd7b9f7bSTejun Heo */ 233324a56e1STejun Heo void kernfs_get(struct kernfs_node *kn) 234fd7b9f7bSTejun Heo { 235324a56e1STejun Heo if (kn) { 236adc5e8b5STejun Heo WARN_ON(!atomic_read(&kn->count)); 237adc5e8b5STejun Heo atomic_inc(&kn->count); 238fd7b9f7bSTejun Heo } 239fd7b9f7bSTejun Heo } 240fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_get); 241fd7b9f7bSTejun Heo 242fd7b9f7bSTejun Heo /** 243324a56e1STejun Heo * kernfs_put - put a reference count on a kernfs_node 244324a56e1STejun Heo * @kn: the target kernfs_node 245fd7b9f7bSTejun Heo * 246324a56e1STejun Heo * Put a reference count of @kn and destroy it if it reached zero. 247fd7b9f7bSTejun Heo */ 248324a56e1STejun Heo void kernfs_put(struct kernfs_node *kn) 249fd7b9f7bSTejun Heo { 250324a56e1STejun Heo struct kernfs_node *parent; 251ba7443bcSTejun Heo struct kernfs_root *root; 252fd7b9f7bSTejun Heo 253adc5e8b5STejun Heo if (!kn || !atomic_dec_and_test(&kn->count)) 254fd7b9f7bSTejun Heo return; 255324a56e1STejun Heo root = kernfs_root(kn); 256fd7b9f7bSTejun Heo repeat: 25781c173cbSTejun Heo /* 25881c173cbSTejun Heo * Moving/renaming is always done while holding reference. 259adc5e8b5STejun Heo * kn->parent won't change beneath us. 260fd7b9f7bSTejun Heo */ 261adc5e8b5STejun Heo parent = kn->parent; 262fd7b9f7bSTejun Heo 26381c173cbSTejun Heo WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, 26481c173cbSTejun Heo "kernfs_put: %s/%s: released with incorrect active_ref %d\n", 26581c173cbSTejun Heo parent ? parent->name : "", kn->name, atomic_read(&kn->active)); 266fd7b9f7bSTejun Heo 267df23fc39STejun Heo if (kernfs_type(kn) == KERNFS_LINK) 268adc5e8b5STejun Heo kernfs_put(kn->symlink.target_kn); 2692063d608STejun Heo if (!(kn->flags & KERNFS_STATIC_NAME)) 270adc5e8b5STejun Heo kfree(kn->name); 271adc5e8b5STejun Heo if (kn->iattr) { 272adc5e8b5STejun Heo if (kn->iattr->ia_secdata) 273adc5e8b5STejun Heo security_release_secctx(kn->iattr->ia_secdata, 274adc5e8b5STejun Heo kn->iattr->ia_secdata_len); 275adc5e8b5STejun Heo simple_xattrs_free(&kn->iattr->xattrs); 2762322392bSTejun Heo } 277adc5e8b5STejun Heo kfree(kn->iattr); 278adc5e8b5STejun Heo ida_simple_remove(&root->ino_ida, kn->ino); 279a797bfc3STejun Heo kmem_cache_free(kernfs_node_cache, kn); 280fd7b9f7bSTejun Heo 281324a56e1STejun Heo kn = parent; 282324a56e1STejun Heo if (kn) { 283adc5e8b5STejun Heo if (atomic_dec_and_test(&kn->count)) 284fd7b9f7bSTejun Heo goto repeat; 285ba7443bcSTejun Heo } else { 286324a56e1STejun Heo /* just released the root kn, free @root too */ 287bc755553STejun Heo ida_destroy(&root->ino_ida); 288ba7443bcSTejun Heo kfree(root); 289ba7443bcSTejun Heo } 290fd7b9f7bSTejun Heo } 291fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_put); 292fd7b9f7bSTejun Heo 293c637b8acSTejun Heo static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) 294fd7b9f7bSTejun Heo { 295324a56e1STejun Heo struct kernfs_node *kn; 296fd7b9f7bSTejun Heo 297fd7b9f7bSTejun Heo if (flags & LOOKUP_RCU) 298fd7b9f7bSTejun Heo return -ECHILD; 299fd7b9f7bSTejun Heo 30019bbb926STejun Heo /* Always perform fresh lookup for negatives */ 30119bbb926STejun Heo if (!dentry->d_inode) 30219bbb926STejun Heo goto out_bad_unlocked; 30319bbb926STejun Heo 304324a56e1STejun Heo kn = dentry->d_fsdata; 305a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 306fd7b9f7bSTejun Heo 30781c173cbSTejun Heo /* The kernfs node has been deactivated */ 30881c173cbSTejun Heo if (!kernfs_active(kn)) 309fd7b9f7bSTejun Heo goto out_bad; 310fd7b9f7bSTejun Heo 311c637b8acSTejun Heo /* The kernfs node has been moved? */ 312adc5e8b5STejun Heo if (dentry->d_parent->d_fsdata != kn->parent) 313fd7b9f7bSTejun Heo goto out_bad; 314fd7b9f7bSTejun Heo 315c637b8acSTejun Heo /* The kernfs node has been renamed */ 316adc5e8b5STejun Heo if (strcmp(dentry->d_name.name, kn->name) != 0) 317fd7b9f7bSTejun Heo goto out_bad; 318fd7b9f7bSTejun Heo 319c637b8acSTejun Heo /* The kernfs node has been moved to a different namespace */ 320adc5e8b5STejun Heo if (kn->parent && kernfs_ns_enabled(kn->parent) && 321c525aaddSTejun Heo kernfs_info(dentry->d_sb)->ns != kn->ns) 322fd7b9f7bSTejun Heo goto out_bad; 323fd7b9f7bSTejun Heo 324a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 325fd7b9f7bSTejun Heo out_valid: 326fd7b9f7bSTejun Heo return 1; 327fd7b9f7bSTejun Heo out_bad: 328a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 32919bbb926STejun Heo out_bad_unlocked: 33019bbb926STejun Heo /* 33119bbb926STejun Heo * @dentry doesn't match the underlying kernfs node, drop the 33219bbb926STejun Heo * dentry and force lookup. If we have submounts we must allow the 33319bbb926STejun Heo * vfs caches to lie about the state of the filesystem to prevent 33419bbb926STejun Heo * leaks and other nasty things, so use check_submounts_and_drop() 33519bbb926STejun Heo * instead of d_drop(). 336fd7b9f7bSTejun Heo */ 337fd7b9f7bSTejun Heo if (check_submounts_and_drop(dentry) != 0) 338fd7b9f7bSTejun Heo goto out_valid; 339fd7b9f7bSTejun Heo 340fd7b9f7bSTejun Heo return 0; 341fd7b9f7bSTejun Heo } 342fd7b9f7bSTejun Heo 343c637b8acSTejun Heo static void kernfs_dop_release(struct dentry *dentry) 344fd7b9f7bSTejun Heo { 345fd7b9f7bSTejun Heo kernfs_put(dentry->d_fsdata); 346fd7b9f7bSTejun Heo } 347fd7b9f7bSTejun Heo 348a797bfc3STejun Heo const struct dentry_operations kernfs_dops = { 349c637b8acSTejun Heo .d_revalidate = kernfs_dop_revalidate, 350c637b8acSTejun Heo .d_release = kernfs_dop_release, 351fd7b9f7bSTejun Heo }; 352fd7b9f7bSTejun Heo 353db4aad20STejun Heo static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, 354db4aad20STejun Heo const char *name, umode_t mode, 355db4aad20STejun Heo unsigned flags) 356fd7b9f7bSTejun Heo { 357fd7b9f7bSTejun Heo char *dup_name = NULL; 358324a56e1STejun Heo struct kernfs_node *kn; 359bc755553STejun Heo int ret; 360fd7b9f7bSTejun Heo 3612063d608STejun Heo if (!(flags & KERNFS_STATIC_NAME)) { 362fd7b9f7bSTejun Heo name = dup_name = kstrdup(name, GFP_KERNEL); 363fd7b9f7bSTejun Heo if (!name) 364fd7b9f7bSTejun Heo return NULL; 365fd7b9f7bSTejun Heo } 366fd7b9f7bSTejun Heo 367a797bfc3STejun Heo kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL); 368324a56e1STejun Heo if (!kn) 369fd7b9f7bSTejun Heo goto err_out1; 370fd7b9f7bSTejun Heo 371bc755553STejun Heo ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL); 372bc755553STejun Heo if (ret < 0) 373fd7b9f7bSTejun Heo goto err_out2; 374adc5e8b5STejun Heo kn->ino = ret; 375fd7b9f7bSTejun Heo 376adc5e8b5STejun Heo atomic_set(&kn->count, 1); 37781c173cbSTejun Heo atomic_set(&kn->active, KN_DEACTIVATED_BIAS); 37835beab06STejun Heo RB_CLEAR_NODE(&kn->rb); 379fd7b9f7bSTejun Heo 380adc5e8b5STejun Heo kn->name = name; 381adc5e8b5STejun Heo kn->mode = mode; 38281c173cbSTejun Heo kn->flags = flags; 383fd7b9f7bSTejun Heo 384324a56e1STejun Heo return kn; 385fd7b9f7bSTejun Heo 386fd7b9f7bSTejun Heo err_out2: 387a797bfc3STejun Heo kmem_cache_free(kernfs_node_cache, kn); 388fd7b9f7bSTejun Heo err_out1: 389fd7b9f7bSTejun Heo kfree(dup_name); 390fd7b9f7bSTejun Heo return NULL; 391fd7b9f7bSTejun Heo } 392fd7b9f7bSTejun Heo 393db4aad20STejun Heo struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, 394db4aad20STejun Heo const char *name, umode_t mode, 395db4aad20STejun Heo unsigned flags) 396db4aad20STejun Heo { 397db4aad20STejun Heo struct kernfs_node *kn; 398db4aad20STejun Heo 399db4aad20STejun Heo kn = __kernfs_new_node(kernfs_root(parent), name, mode, flags); 400db4aad20STejun Heo if (kn) { 401db4aad20STejun Heo kernfs_get(parent); 402db4aad20STejun Heo kn->parent = parent; 403db4aad20STejun Heo } 404db4aad20STejun Heo return kn; 405db4aad20STejun Heo } 406db4aad20STejun Heo 407fd7b9f7bSTejun Heo /** 408c637b8acSTejun Heo * kernfs_add_one - add kernfs_node to parent without warning 409324a56e1STejun Heo * @kn: kernfs_node to be added 410fd7b9f7bSTejun Heo * 411db4aad20STejun Heo * The caller must already have initialized @kn->parent. This 412db4aad20STejun Heo * function increments nlink of the parent's inode if @kn is a 413db4aad20STejun Heo * directory and link into the children list of the parent. 414fd7b9f7bSTejun Heo * 415fd7b9f7bSTejun Heo * RETURNS: 416fd7b9f7bSTejun Heo * 0 on success, -EEXIST if entry with the given name already 417fd7b9f7bSTejun Heo * exists. 418fd7b9f7bSTejun Heo */ 419988cd7afSTejun Heo int kernfs_add_one(struct kernfs_node *kn) 420fd7b9f7bSTejun Heo { 421db4aad20STejun Heo struct kernfs_node *parent = kn->parent; 422c525aaddSTejun Heo struct kernfs_iattrs *ps_iattr; 423988cd7afSTejun Heo bool has_ns; 424fd7b9f7bSTejun Heo int ret; 425fd7b9f7bSTejun Heo 426988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 427988cd7afSTejun Heo 428988cd7afSTejun Heo ret = -EINVAL; 429988cd7afSTejun Heo has_ns = kernfs_ns_enabled(parent); 430988cd7afSTejun Heo if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 431988cd7afSTejun Heo has_ns ? "required" : "invalid", parent->name, kn->name)) 432988cd7afSTejun Heo goto out_unlock; 433fd7b9f7bSTejun Heo 434df23fc39STejun Heo if (kernfs_type(parent) != KERNFS_DIR) 435988cd7afSTejun Heo goto out_unlock; 436fd7b9f7bSTejun Heo 437988cd7afSTejun Heo ret = -ENOENT; 43881c173cbSTejun Heo if (!kernfs_active(parent)) 439988cd7afSTejun Heo goto out_unlock; 440798c75a0SGreg Kroah-Hartman 441c637b8acSTejun Heo kn->hash = kernfs_name_hash(kn->name, kn->ns); 442fd7b9f7bSTejun Heo 443c637b8acSTejun Heo ret = kernfs_link_sibling(kn); 444fd7b9f7bSTejun Heo if (ret) 445988cd7afSTejun Heo goto out_unlock; 446fd7b9f7bSTejun Heo 447fd7b9f7bSTejun Heo /* Update timestamps on the parent */ 448adc5e8b5STejun Heo ps_iattr = parent->iattr; 449fd7b9f7bSTejun Heo if (ps_iattr) { 450fd7b9f7bSTejun Heo struct iattr *ps_iattrs = &ps_iattr->ia_iattr; 451fd7b9f7bSTejun Heo ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; 452fd7b9f7bSTejun Heo } 453fd7b9f7bSTejun Heo 454fd7b9f7bSTejun Heo /* Mark the entry added into directory tree */ 45581c173cbSTejun Heo atomic_sub(KN_DEACTIVATED_BIAS, &kn->active); 456988cd7afSTejun Heo ret = 0; 457988cd7afSTejun Heo out_unlock: 458a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 459988cd7afSTejun Heo return ret; 460fd7b9f7bSTejun Heo } 461fd7b9f7bSTejun Heo 462fd7b9f7bSTejun Heo /** 463324a56e1STejun Heo * kernfs_find_ns - find kernfs_node with the given name 464324a56e1STejun Heo * @parent: kernfs_node to search under 465fd7b9f7bSTejun Heo * @name: name to look for 466fd7b9f7bSTejun Heo * @ns: the namespace tag to use 467fd7b9f7bSTejun Heo * 468324a56e1STejun Heo * Look for kernfs_node with name @name under @parent. Returns pointer to 469324a56e1STejun Heo * the found kernfs_node on success, %NULL on failure. 470fd7b9f7bSTejun Heo */ 471324a56e1STejun Heo static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, 472fd7b9f7bSTejun Heo const unsigned char *name, 473fd7b9f7bSTejun Heo const void *ns) 474fd7b9f7bSTejun Heo { 475adc5e8b5STejun Heo struct rb_node *node = parent->dir.children.rb_node; 476ac9bba03STejun Heo bool has_ns = kernfs_ns_enabled(parent); 477fd7b9f7bSTejun Heo unsigned int hash; 478fd7b9f7bSTejun Heo 479a797bfc3STejun Heo lockdep_assert_held(&kernfs_mutex); 480fd7b9f7bSTejun Heo 481fd7b9f7bSTejun Heo if (has_ns != (bool)ns) { 482c637b8acSTejun Heo WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", 483adc5e8b5STejun Heo has_ns ? "required" : "invalid", parent->name, name); 484fd7b9f7bSTejun Heo return NULL; 485fd7b9f7bSTejun Heo } 486fd7b9f7bSTejun Heo 487c637b8acSTejun Heo hash = kernfs_name_hash(name, ns); 488fd7b9f7bSTejun Heo while (node) { 489324a56e1STejun Heo struct kernfs_node *kn; 490fd7b9f7bSTejun Heo int result; 491fd7b9f7bSTejun Heo 492324a56e1STejun Heo kn = rb_to_kn(node); 493c637b8acSTejun Heo result = kernfs_name_compare(hash, name, ns, kn); 494fd7b9f7bSTejun Heo if (result < 0) 495fd7b9f7bSTejun Heo node = node->rb_left; 496fd7b9f7bSTejun Heo else if (result > 0) 497fd7b9f7bSTejun Heo node = node->rb_right; 498fd7b9f7bSTejun Heo else 499324a56e1STejun Heo return kn; 500fd7b9f7bSTejun Heo } 501fd7b9f7bSTejun Heo return NULL; 502fd7b9f7bSTejun Heo } 503fd7b9f7bSTejun Heo 504fd7b9f7bSTejun Heo /** 505324a56e1STejun Heo * kernfs_find_and_get_ns - find and get kernfs_node with the given name 506324a56e1STejun Heo * @parent: kernfs_node to search under 507fd7b9f7bSTejun Heo * @name: name to look for 508fd7b9f7bSTejun Heo * @ns: the namespace tag to use 509fd7b9f7bSTejun Heo * 510324a56e1STejun Heo * Look for kernfs_node with name @name under @parent and get a reference 511fd7b9f7bSTejun Heo * if found. This function may sleep and returns pointer to the found 512324a56e1STejun Heo * kernfs_node on success, %NULL on failure. 513fd7b9f7bSTejun Heo */ 514324a56e1STejun Heo struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, 515fd7b9f7bSTejun Heo const char *name, const void *ns) 516fd7b9f7bSTejun Heo { 517324a56e1STejun Heo struct kernfs_node *kn; 518fd7b9f7bSTejun Heo 519a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 520324a56e1STejun Heo kn = kernfs_find_ns(parent, name, ns); 521324a56e1STejun Heo kernfs_get(kn); 522a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 523fd7b9f7bSTejun Heo 524324a56e1STejun Heo return kn; 525fd7b9f7bSTejun Heo } 526fd7b9f7bSTejun Heo EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); 527fd7b9f7bSTejun Heo 528fd7b9f7bSTejun Heo /** 529ba7443bcSTejun Heo * kernfs_create_root - create a new kernfs hierarchy 53080b9bbefSTejun Heo * @kdops: optional directory syscall operations for the hierarchy 531ba7443bcSTejun Heo * @priv: opaque data associated with the new directory 532ba7443bcSTejun Heo * 533ba7443bcSTejun Heo * Returns the root of the new hierarchy on success, ERR_PTR() value on 534ba7443bcSTejun Heo * failure. 535ba7443bcSTejun Heo */ 53680b9bbefSTejun Heo struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv) 537ba7443bcSTejun Heo { 538ba7443bcSTejun Heo struct kernfs_root *root; 539324a56e1STejun Heo struct kernfs_node *kn; 540ba7443bcSTejun Heo 541ba7443bcSTejun Heo root = kzalloc(sizeof(*root), GFP_KERNEL); 542ba7443bcSTejun Heo if (!root) 543ba7443bcSTejun Heo return ERR_PTR(-ENOMEM); 544ba7443bcSTejun Heo 545bc755553STejun Heo ida_init(&root->ino_ida); 546bc755553STejun Heo 547db4aad20STejun Heo kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, 548db4aad20STejun Heo KERNFS_DIR); 549324a56e1STejun Heo if (!kn) { 550bc755553STejun Heo ida_destroy(&root->ino_ida); 551ba7443bcSTejun Heo kfree(root); 552ba7443bcSTejun Heo return ERR_PTR(-ENOMEM); 553ba7443bcSTejun Heo } 554ba7443bcSTejun Heo 55581c173cbSTejun Heo atomic_sub(KN_DEACTIVATED_BIAS, &kn->active); 556324a56e1STejun Heo kn->priv = priv; 557adc5e8b5STejun Heo kn->dir.root = root; 558ba7443bcSTejun Heo 55980b9bbefSTejun Heo root->dir_ops = kdops; 560324a56e1STejun Heo root->kn = kn; 561abd54f02STejun Heo init_waitqueue_head(&root->deactivate_waitq); 562ba7443bcSTejun Heo 563ba7443bcSTejun Heo return root; 564ba7443bcSTejun Heo } 565ba7443bcSTejun Heo 566ba7443bcSTejun Heo /** 567ba7443bcSTejun Heo * kernfs_destroy_root - destroy a kernfs hierarchy 568ba7443bcSTejun Heo * @root: root of the hierarchy to destroy 569ba7443bcSTejun Heo * 570ba7443bcSTejun Heo * Destroy the hierarchy anchored at @root by removing all existing 571ba7443bcSTejun Heo * directories and destroying @root. 572ba7443bcSTejun Heo */ 573ba7443bcSTejun Heo void kernfs_destroy_root(struct kernfs_root *root) 574ba7443bcSTejun Heo { 575324a56e1STejun Heo kernfs_remove(root->kn); /* will also free @root */ 576ba7443bcSTejun Heo } 577ba7443bcSTejun Heo 578ba7443bcSTejun Heo /** 579fd7b9f7bSTejun Heo * kernfs_create_dir_ns - create a directory 580fd7b9f7bSTejun Heo * @parent: parent in which to create a new directory 581fd7b9f7bSTejun Heo * @name: name of the new directory 582bb8b9d09STejun Heo * @mode: mode of the new directory 583fd7b9f7bSTejun Heo * @priv: opaque data associated with the new directory 584fd7b9f7bSTejun Heo * @ns: optional namespace tag of the directory 585fd7b9f7bSTejun Heo * 586fd7b9f7bSTejun Heo * Returns the created node on success, ERR_PTR() value on failure. 587fd7b9f7bSTejun Heo */ 588324a56e1STejun Heo struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, 589bb8b9d09STejun Heo const char *name, umode_t mode, 590bb8b9d09STejun Heo void *priv, const void *ns) 591fd7b9f7bSTejun Heo { 592324a56e1STejun Heo struct kernfs_node *kn; 593fd7b9f7bSTejun Heo int rc; 594fd7b9f7bSTejun Heo 595fd7b9f7bSTejun Heo /* allocate */ 596db4aad20STejun Heo kn = kernfs_new_node(parent, name, mode | S_IFDIR, KERNFS_DIR); 597324a56e1STejun Heo if (!kn) 598fd7b9f7bSTejun Heo return ERR_PTR(-ENOMEM); 599fd7b9f7bSTejun Heo 600adc5e8b5STejun Heo kn->dir.root = parent->dir.root; 601adc5e8b5STejun Heo kn->ns = ns; 602324a56e1STejun Heo kn->priv = priv; 603fd7b9f7bSTejun Heo 604fd7b9f7bSTejun Heo /* link in */ 605988cd7afSTejun Heo rc = kernfs_add_one(kn); 606fd7b9f7bSTejun Heo if (!rc) 607324a56e1STejun Heo return kn; 608fd7b9f7bSTejun Heo 609324a56e1STejun Heo kernfs_put(kn); 610fd7b9f7bSTejun Heo return ERR_PTR(rc); 611fd7b9f7bSTejun Heo } 612fd7b9f7bSTejun Heo 613c637b8acSTejun Heo static struct dentry *kernfs_iop_lookup(struct inode *dir, 614c637b8acSTejun Heo struct dentry *dentry, 615fd7b9f7bSTejun Heo unsigned int flags) 616fd7b9f7bSTejun Heo { 61719bbb926STejun Heo struct dentry *ret; 618324a56e1STejun Heo struct kernfs_node *parent = dentry->d_parent->d_fsdata; 619324a56e1STejun Heo struct kernfs_node *kn; 620fd7b9f7bSTejun Heo struct inode *inode; 621fd7b9f7bSTejun Heo const void *ns = NULL; 622fd7b9f7bSTejun Heo 623a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 624fd7b9f7bSTejun Heo 625324a56e1STejun Heo if (kernfs_ns_enabled(parent)) 626c525aaddSTejun Heo ns = kernfs_info(dir->i_sb)->ns; 627fd7b9f7bSTejun Heo 628324a56e1STejun Heo kn = kernfs_find_ns(parent, dentry->d_name.name, ns); 629fd7b9f7bSTejun Heo 630fd7b9f7bSTejun Heo /* no such entry */ 631324a56e1STejun Heo if (!kn) { 63219bbb926STejun Heo ret = NULL; 633fd7b9f7bSTejun Heo goto out_unlock; 634fd7b9f7bSTejun Heo } 635324a56e1STejun Heo kernfs_get(kn); 636324a56e1STejun Heo dentry->d_fsdata = kn; 637fd7b9f7bSTejun Heo 638fd7b9f7bSTejun Heo /* attach dentry and inode */ 639c637b8acSTejun Heo inode = kernfs_get_inode(dir->i_sb, kn); 640fd7b9f7bSTejun Heo if (!inode) { 641fd7b9f7bSTejun Heo ret = ERR_PTR(-ENOMEM); 642fd7b9f7bSTejun Heo goto out_unlock; 643fd7b9f7bSTejun Heo } 644fd7b9f7bSTejun Heo 645fd7b9f7bSTejun Heo /* instantiate and hash dentry */ 646fd7b9f7bSTejun Heo ret = d_materialise_unique(dentry, inode); 647fd7b9f7bSTejun Heo out_unlock: 648a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 649fd7b9f7bSTejun Heo return ret; 650fd7b9f7bSTejun Heo } 651fd7b9f7bSTejun Heo 65280b9bbefSTejun Heo static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry, 65380b9bbefSTejun Heo umode_t mode) 65480b9bbefSTejun Heo { 65580b9bbefSTejun Heo struct kernfs_node *parent = dir->i_private; 65680b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops; 65780b9bbefSTejun Heo 65880b9bbefSTejun Heo if (!kdops || !kdops->mkdir) 65980b9bbefSTejun Heo return -EPERM; 66080b9bbefSTejun Heo 66180b9bbefSTejun Heo return kdops->mkdir(parent, dentry->d_name.name, mode); 66280b9bbefSTejun Heo } 66380b9bbefSTejun Heo 66480b9bbefSTejun Heo static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) 66580b9bbefSTejun Heo { 66680b9bbefSTejun Heo struct kernfs_node *kn = dentry->d_fsdata; 66780b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops; 66880b9bbefSTejun Heo 66980b9bbefSTejun Heo if (!kdops || !kdops->rmdir) 67080b9bbefSTejun Heo return -EPERM; 67180b9bbefSTejun Heo 67280b9bbefSTejun Heo return kdops->rmdir(kn); 67380b9bbefSTejun Heo } 67480b9bbefSTejun Heo 67580b9bbefSTejun Heo static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry, 67680b9bbefSTejun Heo struct inode *new_dir, struct dentry *new_dentry) 67780b9bbefSTejun Heo { 67880b9bbefSTejun Heo struct kernfs_node *kn = old_dentry->d_fsdata; 67980b9bbefSTejun Heo struct kernfs_node *new_parent = new_dir->i_private; 68080b9bbefSTejun Heo struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops; 68180b9bbefSTejun Heo 68280b9bbefSTejun Heo if (!kdops || !kdops->rename) 68380b9bbefSTejun Heo return -EPERM; 68480b9bbefSTejun Heo 68580b9bbefSTejun Heo return kdops->rename(kn, new_parent, new_dentry->d_name.name); 68680b9bbefSTejun Heo } 68780b9bbefSTejun Heo 688a797bfc3STejun Heo const struct inode_operations kernfs_dir_iops = { 689c637b8acSTejun Heo .lookup = kernfs_iop_lookup, 690c637b8acSTejun Heo .permission = kernfs_iop_permission, 691c637b8acSTejun Heo .setattr = kernfs_iop_setattr, 692c637b8acSTejun Heo .getattr = kernfs_iop_getattr, 693c637b8acSTejun Heo .setxattr = kernfs_iop_setxattr, 694c637b8acSTejun Heo .removexattr = kernfs_iop_removexattr, 695c637b8acSTejun Heo .getxattr = kernfs_iop_getxattr, 696c637b8acSTejun Heo .listxattr = kernfs_iop_listxattr, 69780b9bbefSTejun Heo 69880b9bbefSTejun Heo .mkdir = kernfs_iop_mkdir, 69980b9bbefSTejun Heo .rmdir = kernfs_iop_rmdir, 70080b9bbefSTejun Heo .rename = kernfs_iop_rename, 701fd7b9f7bSTejun Heo }; 702fd7b9f7bSTejun Heo 703c637b8acSTejun Heo static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos) 704fd7b9f7bSTejun Heo { 705324a56e1STejun Heo struct kernfs_node *last; 706fd7b9f7bSTejun Heo 707fd7b9f7bSTejun Heo while (true) { 708fd7b9f7bSTejun Heo struct rb_node *rbn; 709fd7b9f7bSTejun Heo 710fd7b9f7bSTejun Heo last = pos; 711fd7b9f7bSTejun Heo 712df23fc39STejun Heo if (kernfs_type(pos) != KERNFS_DIR) 713fd7b9f7bSTejun Heo break; 714fd7b9f7bSTejun Heo 715adc5e8b5STejun Heo rbn = rb_first(&pos->dir.children); 716fd7b9f7bSTejun Heo if (!rbn) 717fd7b9f7bSTejun Heo break; 718fd7b9f7bSTejun Heo 719324a56e1STejun Heo pos = rb_to_kn(rbn); 720fd7b9f7bSTejun Heo } 721fd7b9f7bSTejun Heo 722fd7b9f7bSTejun Heo return last; 723fd7b9f7bSTejun Heo } 724fd7b9f7bSTejun Heo 725fd7b9f7bSTejun Heo /** 726c637b8acSTejun Heo * kernfs_next_descendant_post - find the next descendant for post-order walk 727fd7b9f7bSTejun Heo * @pos: the current position (%NULL to initiate traversal) 728324a56e1STejun Heo * @root: kernfs_node whose descendants to walk 729fd7b9f7bSTejun Heo * 730fd7b9f7bSTejun Heo * Find the next descendant to visit for post-order traversal of @root's 731fd7b9f7bSTejun Heo * descendants. @root is included in the iteration and the last node to be 732fd7b9f7bSTejun Heo * visited. 733fd7b9f7bSTejun Heo */ 734c637b8acSTejun Heo static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, 735324a56e1STejun Heo struct kernfs_node *root) 736fd7b9f7bSTejun Heo { 737fd7b9f7bSTejun Heo struct rb_node *rbn; 738fd7b9f7bSTejun Heo 739a797bfc3STejun Heo lockdep_assert_held(&kernfs_mutex); 740fd7b9f7bSTejun Heo 741fd7b9f7bSTejun Heo /* if first iteration, visit leftmost descendant which may be root */ 742fd7b9f7bSTejun Heo if (!pos) 743c637b8acSTejun Heo return kernfs_leftmost_descendant(root); 744fd7b9f7bSTejun Heo 745fd7b9f7bSTejun Heo /* if we visited @root, we're done */ 746fd7b9f7bSTejun Heo if (pos == root) 747fd7b9f7bSTejun Heo return NULL; 748fd7b9f7bSTejun Heo 749fd7b9f7bSTejun Heo /* if there's an unvisited sibling, visit its leftmost descendant */ 750adc5e8b5STejun Heo rbn = rb_next(&pos->rb); 751fd7b9f7bSTejun Heo if (rbn) 752c637b8acSTejun Heo return kernfs_leftmost_descendant(rb_to_kn(rbn)); 753fd7b9f7bSTejun Heo 754fd7b9f7bSTejun Heo /* no sibling left, visit parent */ 755adc5e8b5STejun Heo return pos->parent; 756fd7b9f7bSTejun Heo } 757fd7b9f7bSTejun Heo 758988cd7afSTejun Heo static void __kernfs_remove(struct kernfs_node *kn) 759fd7b9f7bSTejun Heo { 76035beab06STejun Heo struct kernfs_node *pos; 76135beab06STejun Heo 76235beab06STejun Heo lockdep_assert_held(&kernfs_mutex); 763fd7b9f7bSTejun Heo 764ce9b499cSGreg Kroah-Hartman if (!kn) 765ce9b499cSGreg Kroah-Hartman return; 766ce9b499cSGreg Kroah-Hartman 767c637b8acSTejun Heo pr_debug("kernfs %s: removing\n", kn->name); 768fd7b9f7bSTejun Heo 76981c173cbSTejun Heo /* prevent any new usage under @kn by deactivating all nodes */ 77035beab06STejun Heo pos = NULL; 77135beab06STejun Heo while ((pos = kernfs_next_descendant_post(pos, kn))) 77281c173cbSTejun Heo if (kernfs_active(pos)) 77381c173cbSTejun Heo atomic_add(KN_DEACTIVATED_BIAS, &pos->active); 77435beab06STejun Heo 77535beab06STejun Heo /* deactivate and unlink the subtree node-by-node */ 776fd7b9f7bSTejun Heo do { 77735beab06STejun Heo pos = kernfs_leftmost_descendant(kn); 77835beab06STejun Heo 77935beab06STejun Heo /* 78081c173cbSTejun Heo * kernfs_drain() drops kernfs_mutex temporarily and @pos's 78181c173cbSTejun Heo * base ref could have been put by someone else by the time 78281c173cbSTejun Heo * the function returns. Make sure it doesn't go away 78381c173cbSTejun Heo * underneath us. 78435beab06STejun Heo */ 78535beab06STejun Heo kernfs_get(pos); 78635beab06STejun Heo 78781c173cbSTejun Heo kernfs_drain(pos); 78835beab06STejun Heo 78935beab06STejun Heo /* 79035beab06STejun Heo * kernfs_unlink_sibling() succeeds once per node. Use it 79135beab06STejun Heo * to decide who's responsible for cleanups. 79235beab06STejun Heo */ 79335beab06STejun Heo if (!pos->parent || kernfs_unlink_sibling(pos)) { 79435beab06STejun Heo struct kernfs_iattrs *ps_iattr = 79535beab06STejun Heo pos->parent ? pos->parent->iattr : NULL; 79635beab06STejun Heo 79735beab06STejun Heo /* update timestamps on the parent */ 79835beab06STejun Heo if (ps_iattr) { 79935beab06STejun Heo ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME; 80035beab06STejun Heo ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME; 80135beab06STejun Heo } 80235beab06STejun Heo 803988cd7afSTejun Heo kernfs_put(pos); 80435beab06STejun Heo } 80535beab06STejun Heo 80635beab06STejun Heo kernfs_put(pos); 80735beab06STejun Heo } while (pos != kn); 808fd7b9f7bSTejun Heo } 809fd7b9f7bSTejun Heo 810fd7b9f7bSTejun Heo /** 811324a56e1STejun Heo * kernfs_remove - remove a kernfs_node recursively 812324a56e1STejun Heo * @kn: the kernfs_node to remove 813fd7b9f7bSTejun Heo * 814324a56e1STejun Heo * Remove @kn along with all its subdirectories and files. 815fd7b9f7bSTejun Heo */ 816324a56e1STejun Heo void kernfs_remove(struct kernfs_node *kn) 817fd7b9f7bSTejun Heo { 818988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 819988cd7afSTejun Heo __kernfs_remove(kn); 820988cd7afSTejun Heo mutex_unlock(&kernfs_mutex); 821fd7b9f7bSTejun Heo } 822fd7b9f7bSTejun Heo 823fd7b9f7bSTejun Heo /** 824324a56e1STejun Heo * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it 825324a56e1STejun Heo * @parent: parent of the target 826324a56e1STejun Heo * @name: name of the kernfs_node to remove 827324a56e1STejun Heo * @ns: namespace tag of the kernfs_node to remove 828fd7b9f7bSTejun Heo * 829324a56e1STejun Heo * Look for the kernfs_node with @name and @ns under @parent and remove it. 830324a56e1STejun Heo * Returns 0 on success, -ENOENT if such entry doesn't exist. 831fd7b9f7bSTejun Heo */ 832324a56e1STejun Heo int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, 833fd7b9f7bSTejun Heo const void *ns) 834fd7b9f7bSTejun Heo { 835324a56e1STejun Heo struct kernfs_node *kn; 836fd7b9f7bSTejun Heo 837324a56e1STejun Heo if (!parent) { 838c637b8acSTejun Heo WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n", 839fd7b9f7bSTejun Heo name); 840fd7b9f7bSTejun Heo return -ENOENT; 841fd7b9f7bSTejun Heo } 842fd7b9f7bSTejun Heo 843988cd7afSTejun Heo mutex_lock(&kernfs_mutex); 844fd7b9f7bSTejun Heo 845324a56e1STejun Heo kn = kernfs_find_ns(parent, name, ns); 846324a56e1STejun Heo if (kn) 847988cd7afSTejun Heo __kernfs_remove(kn); 848fd7b9f7bSTejun Heo 849988cd7afSTejun Heo mutex_unlock(&kernfs_mutex); 850fd7b9f7bSTejun Heo 851324a56e1STejun Heo if (kn) 852fd7b9f7bSTejun Heo return 0; 853fd7b9f7bSTejun Heo else 854fd7b9f7bSTejun Heo return -ENOENT; 855fd7b9f7bSTejun Heo } 856fd7b9f7bSTejun Heo 857fd7b9f7bSTejun Heo /** 858fd7b9f7bSTejun Heo * kernfs_rename_ns - move and rename a kernfs_node 859324a56e1STejun Heo * @kn: target node 860fd7b9f7bSTejun Heo * @new_parent: new parent to put @sd under 861fd7b9f7bSTejun Heo * @new_name: new name 862fd7b9f7bSTejun Heo * @new_ns: new namespace tag 863fd7b9f7bSTejun Heo */ 864324a56e1STejun Heo int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, 865fd7b9f7bSTejun Heo const char *new_name, const void *new_ns) 866fd7b9f7bSTejun Heo { 867fd7b9f7bSTejun Heo int error; 868fd7b9f7bSTejun Heo 869ae34372eSTejun Heo mutex_lock(&kernfs_mutex); 870d0ae3d43STejun Heo 871798c75a0SGreg Kroah-Hartman error = -ENOENT; 87281c173cbSTejun Heo if (!kernfs_active(kn) || !kernfs_active(new_parent)) 873798c75a0SGreg Kroah-Hartman goto out; 874798c75a0SGreg Kroah-Hartman 875fd7b9f7bSTejun Heo error = 0; 876adc5e8b5STejun Heo if ((kn->parent == new_parent) && (kn->ns == new_ns) && 877adc5e8b5STejun Heo (strcmp(kn->name, new_name) == 0)) 878798c75a0SGreg Kroah-Hartman goto out; /* nothing to rename */ 879fd7b9f7bSTejun Heo 880fd7b9f7bSTejun Heo error = -EEXIST; 881fd7b9f7bSTejun Heo if (kernfs_find_ns(new_parent, new_name, new_ns)) 882798c75a0SGreg Kroah-Hartman goto out; 883fd7b9f7bSTejun Heo 884324a56e1STejun Heo /* rename kernfs_node */ 885adc5e8b5STejun Heo if (strcmp(kn->name, new_name) != 0) { 886fd7b9f7bSTejun Heo error = -ENOMEM; 887fd7b9f7bSTejun Heo new_name = kstrdup(new_name, GFP_KERNEL); 888fd7b9f7bSTejun Heo if (!new_name) 889798c75a0SGreg Kroah-Hartman goto out; 890fd7b9f7bSTejun Heo 89147a52e91STejun Heo if (kn->flags & KERNFS_STATIC_NAME) 89247a52e91STejun Heo kn->flags &= ~KERNFS_STATIC_NAME; 89347a52e91STejun Heo else 894adc5e8b5STejun Heo kfree(kn->name); 89547a52e91STejun Heo 896adc5e8b5STejun Heo kn->name = new_name; 897fd7b9f7bSTejun Heo } 898fd7b9f7bSTejun Heo 899fd7b9f7bSTejun Heo /* 900fd7b9f7bSTejun Heo * Move to the appropriate place in the appropriate directories rbtree. 901fd7b9f7bSTejun Heo */ 902c637b8acSTejun Heo kernfs_unlink_sibling(kn); 903fd7b9f7bSTejun Heo kernfs_get(new_parent); 904adc5e8b5STejun Heo kernfs_put(kn->parent); 905adc5e8b5STejun Heo kn->ns = new_ns; 906c637b8acSTejun Heo kn->hash = kernfs_name_hash(kn->name, kn->ns); 907adc5e8b5STejun Heo kn->parent = new_parent; 908c637b8acSTejun Heo kernfs_link_sibling(kn); 909fd7b9f7bSTejun Heo 910fd7b9f7bSTejun Heo error = 0; 911ae34372eSTejun Heo out: 912798c75a0SGreg Kroah-Hartman mutex_unlock(&kernfs_mutex); 913fd7b9f7bSTejun Heo return error; 914fd7b9f7bSTejun Heo } 915fd7b9f7bSTejun Heo 916fd7b9f7bSTejun Heo /* Relationship between s_mode and the DT_xxx types */ 917324a56e1STejun Heo static inline unsigned char dt_type(struct kernfs_node *kn) 918fd7b9f7bSTejun Heo { 919adc5e8b5STejun Heo return (kn->mode >> 12) & 15; 920fd7b9f7bSTejun Heo } 921fd7b9f7bSTejun Heo 922c637b8acSTejun Heo static int kernfs_dir_fop_release(struct inode *inode, struct file *filp) 923fd7b9f7bSTejun Heo { 924fd7b9f7bSTejun Heo kernfs_put(filp->private_data); 925fd7b9f7bSTejun Heo return 0; 926fd7b9f7bSTejun Heo } 927fd7b9f7bSTejun Heo 928c637b8acSTejun Heo static struct kernfs_node *kernfs_dir_pos(const void *ns, 929324a56e1STejun Heo struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) 930fd7b9f7bSTejun Heo { 931fd7b9f7bSTejun Heo if (pos) { 93281c173cbSTejun Heo int valid = kernfs_active(pos) && 933798c75a0SGreg Kroah-Hartman pos->parent == parent && hash == pos->hash; 934fd7b9f7bSTejun Heo kernfs_put(pos); 935fd7b9f7bSTejun Heo if (!valid) 936fd7b9f7bSTejun Heo pos = NULL; 937fd7b9f7bSTejun Heo } 938fd7b9f7bSTejun Heo if (!pos && (hash > 1) && (hash < INT_MAX)) { 939adc5e8b5STejun Heo struct rb_node *node = parent->dir.children.rb_node; 940fd7b9f7bSTejun Heo while (node) { 941324a56e1STejun Heo pos = rb_to_kn(node); 942fd7b9f7bSTejun Heo 943adc5e8b5STejun Heo if (hash < pos->hash) 944fd7b9f7bSTejun Heo node = node->rb_left; 945adc5e8b5STejun Heo else if (hash > pos->hash) 946fd7b9f7bSTejun Heo node = node->rb_right; 947fd7b9f7bSTejun Heo else 948fd7b9f7bSTejun Heo break; 949fd7b9f7bSTejun Heo } 950fd7b9f7bSTejun Heo } 951fd7b9f7bSTejun Heo /* Skip over entries in the wrong namespace */ 952adc5e8b5STejun Heo while (pos && pos->ns != ns) { 953adc5e8b5STejun Heo struct rb_node *node = rb_next(&pos->rb); 954fd7b9f7bSTejun Heo if (!node) 955fd7b9f7bSTejun Heo pos = NULL; 956fd7b9f7bSTejun Heo else 957324a56e1STejun Heo pos = rb_to_kn(node); 958fd7b9f7bSTejun Heo } 959fd7b9f7bSTejun Heo return pos; 960fd7b9f7bSTejun Heo } 961fd7b9f7bSTejun Heo 962c637b8acSTejun Heo static struct kernfs_node *kernfs_dir_next_pos(const void *ns, 963324a56e1STejun Heo struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos) 964fd7b9f7bSTejun Heo { 965c637b8acSTejun Heo pos = kernfs_dir_pos(ns, parent, ino, pos); 966fd7b9f7bSTejun Heo if (pos) 967fd7b9f7bSTejun Heo do { 968adc5e8b5STejun Heo struct rb_node *node = rb_next(&pos->rb); 969fd7b9f7bSTejun Heo if (!node) 970fd7b9f7bSTejun Heo pos = NULL; 971fd7b9f7bSTejun Heo else 972324a56e1STejun Heo pos = rb_to_kn(node); 973adc5e8b5STejun Heo } while (pos && pos->ns != ns); 974fd7b9f7bSTejun Heo return pos; 975fd7b9f7bSTejun Heo } 976fd7b9f7bSTejun Heo 977c637b8acSTejun Heo static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) 978fd7b9f7bSTejun Heo { 979fd7b9f7bSTejun Heo struct dentry *dentry = file->f_path.dentry; 980324a56e1STejun Heo struct kernfs_node *parent = dentry->d_fsdata; 981324a56e1STejun Heo struct kernfs_node *pos = file->private_data; 982fd7b9f7bSTejun Heo const void *ns = NULL; 983fd7b9f7bSTejun Heo 984fd7b9f7bSTejun Heo if (!dir_emit_dots(file, ctx)) 985fd7b9f7bSTejun Heo return 0; 986a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 987fd7b9f7bSTejun Heo 988324a56e1STejun Heo if (kernfs_ns_enabled(parent)) 989c525aaddSTejun Heo ns = kernfs_info(dentry->d_sb)->ns; 990fd7b9f7bSTejun Heo 991c637b8acSTejun Heo for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos); 992fd7b9f7bSTejun Heo pos; 993c637b8acSTejun Heo pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) { 994adc5e8b5STejun Heo const char *name = pos->name; 995fd7b9f7bSTejun Heo unsigned int type = dt_type(pos); 996fd7b9f7bSTejun Heo int len = strlen(name); 997adc5e8b5STejun Heo ino_t ino = pos->ino; 998fd7b9f7bSTejun Heo 999adc5e8b5STejun Heo ctx->pos = pos->hash; 1000fd7b9f7bSTejun Heo file->private_data = pos; 1001fd7b9f7bSTejun Heo kernfs_get(pos); 1002fd7b9f7bSTejun Heo 1003a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 1004fd7b9f7bSTejun Heo if (!dir_emit(ctx, name, len, ino, type)) 1005fd7b9f7bSTejun Heo return 0; 1006a797bfc3STejun Heo mutex_lock(&kernfs_mutex); 1007fd7b9f7bSTejun Heo } 1008a797bfc3STejun Heo mutex_unlock(&kernfs_mutex); 1009fd7b9f7bSTejun Heo file->private_data = NULL; 1010fd7b9f7bSTejun Heo ctx->pos = INT_MAX; 1011fd7b9f7bSTejun Heo return 0; 1012fd7b9f7bSTejun Heo } 1013fd7b9f7bSTejun Heo 1014c637b8acSTejun Heo static loff_t kernfs_dir_fop_llseek(struct file *file, loff_t offset, 1015c637b8acSTejun Heo int whence) 1016fd7b9f7bSTejun Heo { 1017fd7b9f7bSTejun Heo struct inode *inode = file_inode(file); 1018fd7b9f7bSTejun Heo loff_t ret; 1019fd7b9f7bSTejun Heo 1020fd7b9f7bSTejun Heo mutex_lock(&inode->i_mutex); 1021fd7b9f7bSTejun Heo ret = generic_file_llseek(file, offset, whence); 1022fd7b9f7bSTejun Heo mutex_unlock(&inode->i_mutex); 1023fd7b9f7bSTejun Heo 1024fd7b9f7bSTejun Heo return ret; 1025fd7b9f7bSTejun Heo } 1026fd7b9f7bSTejun Heo 1027a797bfc3STejun Heo const struct file_operations kernfs_dir_fops = { 1028fd7b9f7bSTejun Heo .read = generic_read_dir, 1029c637b8acSTejun Heo .iterate = kernfs_fop_readdir, 1030c637b8acSTejun Heo .release = kernfs_dir_fop_release, 1031c637b8acSTejun Heo .llseek = kernfs_dir_fop_llseek, 1032fd7b9f7bSTejun Heo }; 1033