162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Common code for control of lockd and nfsv4 grace periods. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Transplanted from lockd code 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <net/net_namespace.h> 1062306a36Sopenharmony_ci#include <net/netns/generic.h> 1162306a36Sopenharmony_ci#include <linux/fs.h> 1262306a36Sopenharmony_ci#include <linux/filelock.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic unsigned int grace_net_id; 1562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(grace_lock); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/** 1862306a36Sopenharmony_ci * locks_start_grace 1962306a36Sopenharmony_ci * @net: net namespace that this lock manager belongs to 2062306a36Sopenharmony_ci * @lm: who this grace period is for 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * A grace period is a period during which locks should not be given 2362306a36Sopenharmony_ci * out. Currently grace periods are only enforced by the two lock 2462306a36Sopenharmony_ci * managers (lockd and nfsd), using the locks_in_grace() function to 2562306a36Sopenharmony_ci * check when they are in a grace period. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * This function is called to start a grace period. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_civoid 3062306a36Sopenharmony_cilocks_start_grace(struct net *net, struct lock_manager *lm) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct list_head *grace_list = net_generic(net, grace_net_id); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci spin_lock(&grace_lock); 3562306a36Sopenharmony_ci if (list_empty(&lm->list)) 3662306a36Sopenharmony_ci list_add(&lm->list, grace_list); 3762306a36Sopenharmony_ci else 3862306a36Sopenharmony_ci WARN(1, "double list_add attempt detected in net %x %s\n", 3962306a36Sopenharmony_ci net->ns.inum, (net == &init_net) ? "(init_net)" : ""); 4062306a36Sopenharmony_ci spin_unlock(&grace_lock); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_start_grace); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/** 4562306a36Sopenharmony_ci * locks_end_grace 4662306a36Sopenharmony_ci * @lm: who this grace period is for 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Call this function to state that the given lock manager is ready to 4962306a36Sopenharmony_ci * resume regular locking. The grace period will not end until all lock 5062306a36Sopenharmony_ci * managers that called locks_start_grace() also call locks_end_grace(). 5162306a36Sopenharmony_ci * Note that callers count on it being safe to call this more than once, 5262306a36Sopenharmony_ci * and the second call should be a no-op. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_civoid 5562306a36Sopenharmony_cilocks_end_grace(struct lock_manager *lm) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci spin_lock(&grace_lock); 5862306a36Sopenharmony_ci list_del_init(&lm->list); 5962306a36Sopenharmony_ci spin_unlock(&grace_lock); 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_end_grace); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic bool 6462306a36Sopenharmony_ci__state_in_grace(struct net *net, bool open) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct list_head *grace_list = net_generic(net, grace_net_id); 6762306a36Sopenharmony_ci struct lock_manager *lm; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (!open) 7062306a36Sopenharmony_ci return !list_empty(grace_list); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci spin_lock(&grace_lock); 7362306a36Sopenharmony_ci list_for_each_entry(lm, grace_list, list) { 7462306a36Sopenharmony_ci if (lm->block_opens) { 7562306a36Sopenharmony_ci spin_unlock(&grace_lock); 7662306a36Sopenharmony_ci return true; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci spin_unlock(&grace_lock); 8062306a36Sopenharmony_ci return false; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/** 8462306a36Sopenharmony_ci * locks_in_grace 8562306a36Sopenharmony_ci * @net: network namespace 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * Lock managers call this function to determine when it is OK for them 8862306a36Sopenharmony_ci * to answer ordinary lock requests, and when they should accept only 8962306a36Sopenharmony_ci * lock reclaims. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cibool locks_in_grace(struct net *net) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci return __state_in_grace(net, false); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_in_grace); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cibool opens_in_grace(struct net *net) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return __state_in_grace(net, true); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(opens_in_grace); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int __net_init 10462306a36Sopenharmony_cigrace_init_net(struct net *net) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct list_head *grace_list = net_generic(net, grace_net_id); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci INIT_LIST_HEAD(grace_list); 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void __net_exit 11362306a36Sopenharmony_cigrace_exit_net(struct net *net) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct list_head *grace_list = net_generic(net, grace_net_id); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci WARN_ONCE(!list_empty(grace_list), 11862306a36Sopenharmony_ci "net %x %s: grace_list is not empty\n", 11962306a36Sopenharmony_ci net->ns.inum, __func__); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic struct pernet_operations grace_net_ops = { 12362306a36Sopenharmony_ci .init = grace_init_net, 12462306a36Sopenharmony_ci .exit = grace_exit_net, 12562306a36Sopenharmony_ci .id = &grace_net_id, 12662306a36Sopenharmony_ci .size = sizeof(struct list_head), 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int __init 13062306a36Sopenharmony_ciinit_grace(void) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci return register_pernet_subsys(&grace_net_ops); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void __exit 13662306a36Sopenharmony_ciexit_grace(void) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci unregister_pernet_subsys(&grace_net_ops); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciMODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>"); 14262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 14362306a36Sopenharmony_cimodule_init(init_grace) 14462306a36Sopenharmony_cimodule_exit(exit_grace) 145