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