1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/fs.h> 3 #include <linux/rculist.h> 4 #include <linux/sched.h> 5 #include <linux/slab.h> 6 #include "internal.h" 7 #include "mount.h" 8 9 static DEFINE_SPINLOCK(pin_lock); 10 11 void pin_remove(struct fs_pin *pin) 12 { 13 spin_lock(&pin_lock); 14 hlist_del_init(&pin->m_list); 15 hlist_del_init(&pin->s_list); 16 spin_unlock(&pin_lock); 17 spin_lock_irq(&pin->wait.lock); 18 pin->done = 1; 19 wake_up_locked(&pin->wait); 20 spin_unlock_irq(&pin->wait.lock); 21 } 22 23 void pin_insert(struct fs_pin *pin, struct vfsmount *m) 24 { 25 spin_lock(&pin_lock); 26 hlist_add_head_rcu(&pin->s_list, &m->mnt_sb->s_pins); 27 hlist_add_head_rcu(&pin->m_list, &real_mount(m)->mnt_pins); 28 spin_unlock(&pin_lock); 29 } 30 31 void pin_kill(struct fs_pin *p) 32 { 33 wait_queue_entry_t wait; 34 35 if (!p) { 36 rcu_read_unlock(); 37 return; 38 } 39 init_wait(&wait); 40 spin_lock_irq(&p->wait.lock); 41 if (likely(!p->done)) { 42 p->done = -1; 43 spin_unlock_irq(&p->wait.lock); 44 rcu_read_unlock(); 45 p->kill(p); 46 return; 47 } 48 if (p->done > 0) { 49 spin_unlock_irq(&p->wait.lock); 50 rcu_read_unlock(); 51 return; 52 } 53 __add_wait_queue(&p->wait, &wait); 54 while (1) { 55 set_current_state(TASK_UNINTERRUPTIBLE); 56 spin_unlock_irq(&p->wait.lock); 57 rcu_read_unlock(); 58 schedule(); 59 rcu_read_lock(); 60 if (likely(list_empty(&wait.entry))) 61 break; 62 /* OK, we know p couldn't have been freed yet */ 63 spin_lock_irq(&p->wait.lock); 64 if (p->done > 0) { 65 spin_unlock_irq(&p->wait.lock); 66 break; 67 } 68 } 69 rcu_read_unlock(); 70 } 71 72 void mnt_pin_kill(struct mount *m) 73 { 74 while (1) { 75 struct hlist_node *p; 76 rcu_read_lock(); 77 p = rcu_dereference(hlist_first_rcu(&m->mnt_pins)); 78 if (!p) { 79 rcu_read_unlock(); 80 break; 81 } 82 pin_kill(hlist_entry(p, struct fs_pin, m_list)); 83 } 84 } 85 86 void group_pin_kill(struct hlist_head *p) 87 { 88 while (1) { 89 struct hlist_node *q; 90 rcu_read_lock(); 91 q = rcu_dereference(hlist_first_rcu(p)); 92 if (!q) { 93 rcu_read_unlock(); 94 break; 95 } 96 pin_kill(hlist_entry(q, struct fs_pin, s_list)); 97 } 98 } 99