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 * @net: net namespace that this lock manager belongs to
  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        list_for_each_entry(lm, grace_list, list) {
  73                if (lm->block_opens)
  74                        return true;
  75        }
  76        return false;
  77}
  78
  79/**
  80 * locks_in_grace
  81 *
  82 * Lock managers call this function to determine when it is OK for them
  83 * to answer ordinary lock requests, and when they should accept only
  84 * lock reclaims.
  85 */
  86bool locks_in_grace(struct net *net)
  87{
  88        return __state_in_grace(net, false);
  89}
  90EXPORT_SYMBOL_GPL(locks_in_grace);
  91
  92bool opens_in_grace(struct net *net)
  93{
  94        return __state_in_grace(net, true);
  95}
  96EXPORT_SYMBOL_GPL(opens_in_grace);
  97
  98static int __net_init
  99grace_init_net(struct net *net)
 100{
 101        struct list_head *grace_list = net_generic(net, grace_net_id);
 102
 103        INIT_LIST_HEAD(grace_list);
 104        return 0;
 105}
 106
 107static void __net_exit
 108grace_exit_net(struct net *net)
 109{
 110        struct list_head *grace_list = net_generic(net, grace_net_id);
 111
 112        WARN_ONCE(!list_empty(grace_list),
 113                  "net %x %s: grace_list is not empty\n",
 114                  net->ns.inum, __func__);
 115}
 116
 117static struct pernet_operations grace_net_ops = {
 118        .init = grace_init_net,
 119        .exit = grace_exit_net,
 120        .id   = &grace_net_id,
 121        .size = sizeof(struct list_head),
 122};
 123
 124static int __init
 125init_grace(void)
 126{
 127        return register_pernet_subsys(&grace_net_ops);
 128}
 129
 130static void __exit
 131exit_grace(void)
 132{
 133        unregister_pernet_subsys(&grace_net_ops);
 134}
 135
 136MODULE_AUTHOR("Jeff Layton <jlayton@primarydata.com>");
 137MODULE_LICENSE("GPL");
 138module_init(init_grace)
 139module_exit(exit_grace)
 140