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