162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/fs.h> 362306a36Sopenharmony_ci#include <linux/sched.h> 462306a36Sopenharmony_ci#include <linux/slab.h> 562306a36Sopenharmony_ci#include "internal.h" 662306a36Sopenharmony_ci#include "mount.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_cistatic DEFINE_SPINLOCK(pin_lock); 962306a36Sopenharmony_ci 1062306a36Sopenharmony_civoid pin_remove(struct fs_pin *pin) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci spin_lock(&pin_lock); 1362306a36Sopenharmony_ci hlist_del_init(&pin->m_list); 1462306a36Sopenharmony_ci hlist_del_init(&pin->s_list); 1562306a36Sopenharmony_ci spin_unlock(&pin_lock); 1662306a36Sopenharmony_ci spin_lock_irq(&pin->wait.lock); 1762306a36Sopenharmony_ci pin->done = 1; 1862306a36Sopenharmony_ci wake_up_locked(&pin->wait); 1962306a36Sopenharmony_ci spin_unlock_irq(&pin->wait.lock); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_civoid pin_insert(struct fs_pin *pin, struct vfsmount *m) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci spin_lock(&pin_lock); 2562306a36Sopenharmony_ci hlist_add_head(&pin->s_list, &m->mnt_sb->s_pins); 2662306a36Sopenharmony_ci hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins); 2762306a36Sopenharmony_ci spin_unlock(&pin_lock); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_civoid pin_kill(struct fs_pin *p) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci wait_queue_entry_t wait; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (!p) { 3562306a36Sopenharmony_ci rcu_read_unlock(); 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci init_wait(&wait); 3962306a36Sopenharmony_ci spin_lock_irq(&p->wait.lock); 4062306a36Sopenharmony_ci if (likely(!p->done)) { 4162306a36Sopenharmony_ci p->done = -1; 4262306a36Sopenharmony_ci spin_unlock_irq(&p->wait.lock); 4362306a36Sopenharmony_ci rcu_read_unlock(); 4462306a36Sopenharmony_ci p->kill(p); 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci if (p->done > 0) { 4862306a36Sopenharmony_ci spin_unlock_irq(&p->wait.lock); 4962306a36Sopenharmony_ci rcu_read_unlock(); 5062306a36Sopenharmony_ci return; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci __add_wait_queue(&p->wait, &wait); 5362306a36Sopenharmony_ci while (1) { 5462306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 5562306a36Sopenharmony_ci spin_unlock_irq(&p->wait.lock); 5662306a36Sopenharmony_ci rcu_read_unlock(); 5762306a36Sopenharmony_ci schedule(); 5862306a36Sopenharmony_ci rcu_read_lock(); 5962306a36Sopenharmony_ci if (likely(list_empty(&wait.entry))) 6062306a36Sopenharmony_ci break; 6162306a36Sopenharmony_ci /* OK, we know p couldn't have been freed yet */ 6262306a36Sopenharmony_ci spin_lock_irq(&p->wait.lock); 6362306a36Sopenharmony_ci if (p->done > 0) { 6462306a36Sopenharmony_ci spin_unlock_irq(&p->wait.lock); 6562306a36Sopenharmony_ci break; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci rcu_read_unlock(); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_civoid mnt_pin_kill(struct mount *m) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci while (1) { 7462306a36Sopenharmony_ci struct hlist_node *p; 7562306a36Sopenharmony_ci rcu_read_lock(); 7662306a36Sopenharmony_ci p = READ_ONCE(m->mnt_pins.first); 7762306a36Sopenharmony_ci if (!p) { 7862306a36Sopenharmony_ci rcu_read_unlock(); 7962306a36Sopenharmony_ci break; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci pin_kill(hlist_entry(p, struct fs_pin, m_list)); 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_civoid group_pin_kill(struct hlist_head *p) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci while (1) { 8862306a36Sopenharmony_ci struct hlist_node *q; 8962306a36Sopenharmony_ci rcu_read_lock(); 9062306a36Sopenharmony_ci q = READ_ONCE(p->first); 9162306a36Sopenharmony_ci if (!q) { 9262306a36Sopenharmony_ci rcu_read_unlock(); 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci pin_kill(hlist_entry(q, struct fs_pin, s_list)); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci} 98