1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Common code for control of lockd and nfsv4 grace periods. 4 * 5 * Transplanted from lockd code 6 */ 7 8#include <linux/module.h> 9#include <net/net_namespace.h> 10#include <net/netns/generic.h> 11#include <linux/fs.h> 12#include <linux/filelock.h> 13 14static unsigned int grace_net_id; 15static DEFINE_SPINLOCK(grace_lock); 16 17/** 18 * locks_start_grace 19 * @net: net namespace that this lock manager belongs to 20 * @lm: who this grace period is for 21 * 22 * A grace period is a period during which locks should not be given 23 * out. Currently grace periods are only enforced by the two lock 24 * managers (lockd and nfsd), using the locks_in_grace() function to 25 * check when they are in a grace period. 26 * 27 * This function is called to start a grace period. 28 */ 29void 30locks_start_grace(struct net *net, struct lock_manager *lm) 31{ 32 struct list_head *grace_list = net_generic(net, grace_net_id); 33 34 spin_lock(&grace_lock); 35 if (list_empty(&lm->list)) 36 list_add(&lm->list, grace_list); 37 else 38 WARN(1, "double list_add attempt detected in net %x %s\n", 39 net->ns.inum, (net == &init_net) ? "(init_net)" : ""); 40 spin_unlock(&grace_lock); 41} 42EXPORT_SYMBOL_GPL(locks_start_grace); 43 44/** 45 * locks_end_grace 46 * @lm: who this grace period is for 47 * 48 * Call this function to state that the given lock manager is ready to 49 * resume regular locking. The grace period will not end until all lock 50 * managers that called locks_start_grace() also call locks_end_grace(). 51 * Note that callers count on it being safe to call this more than once, 52 * and the second call should be a no-op. 53 */ 54void 55locks_end_grace(struct lock_manager *lm) 56{ 57 spin_lock(&grace_lock); 58 list_del_init(&lm->list); 59 spin_unlock(&grace_lock); 60} 61EXPORT_SYMBOL_GPL(locks_end_grace); 62 63static bool 64__state_in_grace(struct net *net, bool open) 65{ 66 struct list_head *grace_list = net_generic(net, grace_net_id); 67 struct lock_manager *lm; 68 69 if (!open) 70 return !list_empty(grace_list); 71 72 spin_lock(&grace_lock); 73 list_for_each_entry(lm, grace_list, list) { 74 if (lm->block_opens) { 75 spin_unlock(&grace_lock); 76 return true; 77 } 78 } 79 spin_unlock(&grace_lock); 80 return false; 81} 82 83/** 84 * locks_in_grace 85 * @net: network namespace 86 * 87 * Lock managers call this function to determine when it is OK for them 88 * to answer ordinary lock requests, and when they should accept only 89 * lock reclaims. 90 */ 91bool locks_in_grace(struct net *net) 92{ 93 return __state_in_grace(net, false); 94} 95EXPORT_SYMBOL_GPL(locks_in_grace); 96 97bool opens_in_grace(struct net *net) 98{ 99 return __state_in_grace(net, true); 100} 101EXPORT_SYMBOL_GPL(opens_in_grace); 102 103static int __net_init 104grace_init_net(struct net *net) 105{ 106 struct list_head *grace_list = net_generic(net, grace_net_id); 107 108 INIT_LIST_HEAD(grace_list); 109 return 0; 110} 111 112static void __net_exit 113grace_exit_net(struct net *net) 114{ 115 struct list_head *grace_list = net_generic(net, grace_net_id); 116 117 WARN_ONCE(!list_empty(grace_list), 118 "net %x %s: grace_list is not empty\n", 119 net->ns.inum, __func__); 120} 121 122static struct pernet_operations grace_net_ops = { 123 .init = grace_init_net, 124 .exit = grace_exit_net, 125 .id = &grace_net_id, 126 .size = sizeof(struct list_head), 127}; 128 129static int __init 130init_grace(void) 131{ 132 return register_pernet_subsys(&grace_net_ops); 133} 134 135static void __exit 136exit_grace(void) 137{ 138 unregister_pernet_subsys(&grace_net_ops); 139} 140 141MODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>"); 142MODULE_LICENSE("GPL"); 143module_init(init_grace) 144module_exit(exit_grace) 145