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