18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Common code for control of lockd and nfsv4 grace periods. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Transplanted from lockd code 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 108c2ecf20Sopenharmony_ci#include <net/netns/generic.h> 118c2ecf20Sopenharmony_ci#include <linux/fs.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic unsigned int grace_net_id; 148c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(grace_lock); 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/** 178c2ecf20Sopenharmony_ci * locks_start_grace 188c2ecf20Sopenharmony_ci * @net: net namespace that this lock manager belongs to 198c2ecf20Sopenharmony_ci * @lm: who this grace period is for 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * A grace period is a period during which locks should not be given 228c2ecf20Sopenharmony_ci * out. Currently grace periods are only enforced by the two lock 238c2ecf20Sopenharmony_ci * managers (lockd and nfsd), using the locks_in_grace() function to 248c2ecf20Sopenharmony_ci * check when they are in a grace period. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * This function is called to start a grace period. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_civoid 298c2ecf20Sopenharmony_cilocks_start_grace(struct net *net, struct lock_manager *lm) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci struct list_head *grace_list = net_generic(net, grace_net_id); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci spin_lock(&grace_lock); 348c2ecf20Sopenharmony_ci if (list_empty(&lm->list)) 358c2ecf20Sopenharmony_ci list_add(&lm->list, grace_list); 368c2ecf20Sopenharmony_ci else 378c2ecf20Sopenharmony_ci WARN(1, "double list_add attempt detected in net %x %s\n", 388c2ecf20Sopenharmony_ci net->ns.inum, (net == &init_net) ? "(init_net)" : ""); 398c2ecf20Sopenharmony_ci spin_unlock(&grace_lock); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_start_grace); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * locks_end_grace 458c2ecf20Sopenharmony_ci * @net: net namespace that this lock manager belongs to 468c2ecf20Sopenharmony_ci * @lm: who this grace period is for 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * Call this function to state that the given lock manager is ready to 498c2ecf20Sopenharmony_ci * resume regular locking. The grace period will not end until all lock 508c2ecf20Sopenharmony_ci * managers that called locks_start_grace() also call locks_end_grace(). 518c2ecf20Sopenharmony_ci * Note that callers count on it being safe to call this more than once, 528c2ecf20Sopenharmony_ci * and the second call should be a no-op. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_civoid 558c2ecf20Sopenharmony_cilocks_end_grace(struct lock_manager *lm) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci spin_lock(&grace_lock); 588c2ecf20Sopenharmony_ci list_del_init(&lm->list); 598c2ecf20Sopenharmony_ci spin_unlock(&grace_lock); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_end_grace); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic bool 648c2ecf20Sopenharmony_ci__state_in_grace(struct net *net, bool open) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct list_head *grace_list = net_generic(net, grace_net_id); 678c2ecf20Sopenharmony_ci struct lock_manager *lm; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!open) 708c2ecf20Sopenharmony_ci return !list_empty(grace_list); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci spin_lock(&grace_lock); 738c2ecf20Sopenharmony_ci list_for_each_entry(lm, grace_list, list) { 748c2ecf20Sopenharmony_ci if (lm->block_opens) { 758c2ecf20Sopenharmony_ci spin_unlock(&grace_lock); 768c2ecf20Sopenharmony_ci return true; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci spin_unlock(&grace_lock); 808c2ecf20Sopenharmony_ci return false; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/** 848c2ecf20Sopenharmony_ci * locks_in_grace 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Lock managers call this function to determine when it is OK for them 878c2ecf20Sopenharmony_ci * to answer ordinary lock requests, and when they should accept only 888c2ecf20Sopenharmony_ci * lock reclaims. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cibool locks_in_grace(struct net *net) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci return __state_in_grace(net, false); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(locks_in_grace); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cibool opens_in_grace(struct net *net) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci return __state_in_grace(net, true); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(opens_in_grace); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int __net_init 1038c2ecf20Sopenharmony_cigrace_init_net(struct net *net) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct list_head *grace_list = net_generic(net, grace_net_id); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci INIT_LIST_HEAD(grace_list); 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic void __net_exit 1128c2ecf20Sopenharmony_cigrace_exit_net(struct net *net) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct list_head *grace_list = net_generic(net, grace_net_id); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci WARN_ONCE(!list_empty(grace_list), 1178c2ecf20Sopenharmony_ci "net %x %s: grace_list is not empty\n", 1188c2ecf20Sopenharmony_ci net->ns.inum, __func__); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic struct pernet_operations grace_net_ops = { 1228c2ecf20Sopenharmony_ci .init = grace_init_net, 1238c2ecf20Sopenharmony_ci .exit = grace_exit_net, 1248c2ecf20Sopenharmony_ci .id = &grace_net_id, 1258c2ecf20Sopenharmony_ci .size = sizeof(struct list_head), 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int __init 1298c2ecf20Sopenharmony_ciinit_grace(void) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci return register_pernet_subsys(&grace_net_ops); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void __exit 1358c2ecf20Sopenharmony_ciexit_grace(void) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci unregister_pernet_subsys(&grace_net_ops); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>"); 1418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1428c2ecf20Sopenharmony_cimodule_init(init_grace) 1438c2ecf20Sopenharmony_cimodule_exit(exit_grace) 144