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