18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/fs.h>
38c2ecf20Sopenharmony_ci#include <linux/sched.h>
48c2ecf20Sopenharmony_ci#include <linux/slab.h>
58c2ecf20Sopenharmony_ci#include "internal.h"
68c2ecf20Sopenharmony_ci#include "mount.h"
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(pin_lock);
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_civoid pin_remove(struct fs_pin *pin)
118c2ecf20Sopenharmony_ci{
128c2ecf20Sopenharmony_ci	spin_lock(&pin_lock);
138c2ecf20Sopenharmony_ci	hlist_del_init(&pin->m_list);
148c2ecf20Sopenharmony_ci	hlist_del_init(&pin->s_list);
158c2ecf20Sopenharmony_ci	spin_unlock(&pin_lock);
168c2ecf20Sopenharmony_ci	spin_lock_irq(&pin->wait.lock);
178c2ecf20Sopenharmony_ci	pin->done = 1;
188c2ecf20Sopenharmony_ci	wake_up_locked(&pin->wait);
198c2ecf20Sopenharmony_ci	spin_unlock_irq(&pin->wait.lock);
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_civoid pin_insert(struct fs_pin *pin, struct vfsmount *m)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	spin_lock(&pin_lock);
258c2ecf20Sopenharmony_ci	hlist_add_head(&pin->s_list, &m->mnt_sb->s_pins);
268c2ecf20Sopenharmony_ci	hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins);
278c2ecf20Sopenharmony_ci	spin_unlock(&pin_lock);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_civoid pin_kill(struct fs_pin *p)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	wait_queue_entry_t wait;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	if (!p) {
358c2ecf20Sopenharmony_ci		rcu_read_unlock();
368c2ecf20Sopenharmony_ci		return;
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci	init_wait(&wait);
398c2ecf20Sopenharmony_ci	spin_lock_irq(&p->wait.lock);
408c2ecf20Sopenharmony_ci	if (likely(!p->done)) {
418c2ecf20Sopenharmony_ci		p->done = -1;
428c2ecf20Sopenharmony_ci		spin_unlock_irq(&p->wait.lock);
438c2ecf20Sopenharmony_ci		rcu_read_unlock();
448c2ecf20Sopenharmony_ci		p->kill(p);
458c2ecf20Sopenharmony_ci		return;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci	if (p->done > 0) {
488c2ecf20Sopenharmony_ci		spin_unlock_irq(&p->wait.lock);
498c2ecf20Sopenharmony_ci		rcu_read_unlock();
508c2ecf20Sopenharmony_ci		return;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci	__add_wait_queue(&p->wait, &wait);
538c2ecf20Sopenharmony_ci	while (1) {
548c2ecf20Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
558c2ecf20Sopenharmony_ci		spin_unlock_irq(&p->wait.lock);
568c2ecf20Sopenharmony_ci		rcu_read_unlock();
578c2ecf20Sopenharmony_ci		schedule();
588c2ecf20Sopenharmony_ci		rcu_read_lock();
598c2ecf20Sopenharmony_ci		if (likely(list_empty(&wait.entry)))
608c2ecf20Sopenharmony_ci			break;
618c2ecf20Sopenharmony_ci		/* OK, we know p couldn't have been freed yet */
628c2ecf20Sopenharmony_ci		spin_lock_irq(&p->wait.lock);
638c2ecf20Sopenharmony_ci		if (p->done > 0) {
648c2ecf20Sopenharmony_ci			spin_unlock_irq(&p->wait.lock);
658c2ecf20Sopenharmony_ci			break;
668c2ecf20Sopenharmony_ci		}
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci	rcu_read_unlock();
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_civoid mnt_pin_kill(struct mount *m)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	while (1) {
748c2ecf20Sopenharmony_ci		struct hlist_node *p;
758c2ecf20Sopenharmony_ci		rcu_read_lock();
768c2ecf20Sopenharmony_ci		p = READ_ONCE(m->mnt_pins.first);
778c2ecf20Sopenharmony_ci		if (!p) {
788c2ecf20Sopenharmony_ci			rcu_read_unlock();
798c2ecf20Sopenharmony_ci			break;
808c2ecf20Sopenharmony_ci		}
818c2ecf20Sopenharmony_ci		pin_kill(hlist_entry(p, struct fs_pin, m_list));
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_civoid group_pin_kill(struct hlist_head *p)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	while (1) {
888c2ecf20Sopenharmony_ci		struct hlist_node *q;
898c2ecf20Sopenharmony_ci		rcu_read_lock();
908c2ecf20Sopenharmony_ci		q = READ_ONCE(p->first);
918c2ecf20Sopenharmony_ci		if (!q) {
928c2ecf20Sopenharmony_ci			rcu_read_unlock();
938c2ecf20Sopenharmony_ci			break;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci		pin_kill(hlist_entry(q, struct fs_pin, s_list));
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci}
98