obj-$(CONFIG_LOCKD) += lockd.o
 
 lockd-objs-y := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
-               svcproc.o svcsubs.o mon.o xdr.o
+               svcproc.o svcsubs.o mon.o xdr.o grace.o
 lockd-objs-$(CONFIG_LOCKD_V4) += xdr4.o svc4proc.o
 lockd-objs                   := $(lockd-objs-y)
 
--- /dev/null
+/*
+ * Common code for control of lockd and nfsv4 grace periods.
+ */
+
+#include <linux/module.h>
+#include <linux/lockd/bind.h>
+
+static LIST_HEAD(grace_list);
+static DEFINE_SPINLOCK(grace_lock);
+
+/**
+ * locks_start_grace
+ * @lm: who this grace period is for
+ *
+ * A grace period is a period during which locks should not be given
+ * out.  Currently grace periods are only enforced by the two lock
+ * managers (lockd and nfsd), using the locks_in_grace() function to
+ * check when they are in a grace period.
+ *
+ * This function is called to start a grace period.
+ */
+void locks_start_grace(struct lock_manager *lm)
+{
+       spin_lock(&grace_lock);
+       list_add(&lm->list, &grace_list);
+       spin_unlock(&grace_lock);
+}
+EXPORT_SYMBOL_GPL(locks_start_grace);
+
+/**
+ * locks_end_grace
+ * @lm: who this grace period is for
+ *
+ * Call this function to state that the given lock manager is ready to
+ * resume regular locking.  The grace period will not end until all lock
+ * managers that called locks_start_grace() also call locks_end_grace().
+ * Note that callers count on it being safe to call this more than once,
+ * and the second call should be a no-op.
+ */
+void locks_end_grace(struct lock_manager *lm)
+{
+       spin_lock(&grace_lock);
+       list_del_init(&lm->list);
+       spin_unlock(&grace_lock);
+}
+EXPORT_SYMBOL_GPL(locks_end_grace);
+
+/**
+ * locks_in_grace
+ *
+ * Lock managers call this function to determine when it is OK for them
+ * to answer ordinary lock requests, and when they should accept only
+ * lock reclaims.
+ */
+int locks_in_grace(void)
+{
+       return !list_empty(&grace_list);
+}
+EXPORT_SYMBOL_GPL(locks_in_grace);
 
 static unsigned int            nlmsvc_users;
 static struct task_struct      *nlmsvc_task;
 static struct svc_rqst         *nlmsvc_rqst;
-int                            nlmsvc_grace_period;
 unsigned long                  nlmsvc_timeout;
 
 /*
                return nlm_timeout * 5 * HZ;
 }
 
-unsigned long get_nfs_grace_period(void)
-{
-       unsigned long lockdgrace = get_lockd_grace_period();
-       unsigned long nfsdgrace = 0;
-
-       if (nlmsvc_ops)
-               nfsdgrace = nlmsvc_ops->get_grace_period();
-
-       return max(lockdgrace, nfsdgrace);
-}
-EXPORT_SYMBOL(get_nfs_grace_period);
+static struct lock_manager lockd_manager = {
+};
 
 static void grace_ender(struct work_struct *not_used)
 {
-       nlmsvc_grace_period = 0;
+       locks_end_grace(&lockd_manager);
 }
 
 static DECLARE_DELAYED_WORK(grace_period_end, grace_ender);
 
 static void set_grace_period(void)
 {
-       unsigned long grace_period = get_nfs_grace_period() + jiffies;
+       unsigned long grace_period = get_lockd_grace_period();
 
-       nlmsvc_grace_period = 1;
+       locks_start_grace(&lockd_manager);
        cancel_delayed_work_sync(&grace_period_end);
        schedule_delayed_work(&grace_period_end, grace_period);
 }
 
        resp->cookie = argp->cookie;
 
        /* Don't accept test requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rc;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period && !argp->reclaim) {
+       if (locks_in_grace() && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
                return rc;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period && !argp->reclaim) {
+       if (locks_in_grace() && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
 
        resp->cookie = argp->cookie;
 
        /* Don't accept test requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rc;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period && !argp->reclaim) {
+       if (locks_in_grace() && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
                return rc;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept new lock requests during grace period */
-       if (nlmsvc_grace_period && !argp->reclaim) {
+       if (locks_in_grace() && !argp->reclaim) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
        resp->cookie = argp->cookie;
 
        /* Don't accept requests during grace period */
-       if (nlmsvc_grace_period) {
+       if (locks_in_grace()) {
                resp->status = nlm_lck_denied_grace_period;
                return rpc_success;
        }
 
 static struct nlmsvc_binding   nfsd_nlm_ops = {
        .fopen          = nlm_fopen,            /* open file for locking */
        .fclose         = nlm_fclose,           /* close file */
-       .get_grace_period = get_nfs4_grace_period,
 };
 
 void
 
        /* Openowner is now set, so sequence id will get bumped.  Now we need
         * these checks before we do any creates: */
        status = nfserr_grace;
-       if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+       if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
                goto out;
        status = nfserr_no_grace;
-       if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+       if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
                goto out;
 
        switch (open->op_claim_type) {
 {
        __be32 status;
 
-       if (nfs4_in_grace())
+       if (locks_in_grace())
                return nfserr_grace;
        status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
                             remove->rm_name, remove->rm_namelen);
 
        if (!cstate->save_fh.fh_dentry)
                return status;
-       if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags
+       if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
                                        & NFSEXP_NOSUBTREECHECK))
                return nfserr_grace;
        status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
 
 static time_t lease_time = 90;     /* default lease time */
 static time_t user_lease_time = 90;
 static time_t boot_time;
-static int in_grace = 1;
 static u32 current_ownerid = 1;
 static u32 current_fileid = 1;
 static u32 current_delegid = 1;
                case NFS4_OPEN_CLAIM_NULL:
                        /* Let's not give out any delegations till everyone's
                         * had the chance to reclaim theirs.... */
-                       if (nfs4_in_grace())
+                       if (locks_in_grace())
                                goto out;
                        if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)
                                goto out;
        return status;
 }
 
+struct lock_manager nfsd4_manager = {
+};
+
 static void
-end_grace(void)
+nfsd4_end_grace(void)
 {
        dprintk("NFSD: end of grace period\n");
        nfsd4_recdir_purge_old();
-       in_grace = 0;
+       locks_end_grace(&nfsd4_manager);
 }
 
 static time_t
        nfs4_lock_state();
 
        dprintk("NFSD: laundromat service - starting\n");
-       if (in_grace)
-               end_grace();
+       if (locks_in_grace())
+               nfsd4_end_grace();
        list_for_each_safe(pos, next, &client_lru) {
                clp = list_entry(pos, struct nfs4_client, cl_lru);
                if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
                return nfserr_bad_stateid;
        else if (ONE_STATEID(stateid) && (flags & RD_STATE))
                return nfs_ok;
-       else if (nfs4_in_grace()) {
+       else if (locks_in_grace()) {
                /* Answer in remaining cases depends on existance of
                 * conflicting state; so we must wait out the grace period. */
                return nfserr_grace;
 static inline int
 io_during_grace_disallowed(struct inode *inode, int flags)
 {
-       return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
+       return locks_in_grace() && (flags & (RD_STATE | WR_STATE))
                && mandatory_lock(inode);
 }
 
        filp = lock_stp->st_vfs_file;
 
        status = nfserr_grace;
-       if (nfs4_in_grace() && !lock->lk_reclaim)
+       if (locks_in_grace() && !lock->lk_reclaim)
                goto out;
        status = nfserr_no_grace;
-       if (!nfs4_in_grace() && lock->lk_reclaim)
+       if (!locks_in_grace() && lock->lk_reclaim)
                goto out;
 
        locks_init_lock(&file_lock);
        int error;
        __be32 status;
 
-       if (nfs4_in_grace())
+       if (locks_in_grace())
                return nfserr_grace;
 
        if (check_lock_length(lockt->lt_offset, lockt->lt_length))
        unsigned long grace_time;
 
        boot_time = get_seconds();
-       grace_time = get_nfs_grace_period();
+       grace_time = get_nfs4_grace_period();
        lease_time = user_lease_time;
-       in_grace = 1;
+       locks_start_grace(&nfsd4_manager);
        printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
               grace_time/HZ);
        laundry_wq = create_singlethread_workqueue("nfsd4");
        return;
 }
 
-int
-nfs4_in_grace(void)
-{
-       return in_grace;
-}
-
 time_t
 nfs4_lease_time(void)
 {
 
        int (*fl_change)(struct file_lock **, int);
 };
 
+struct lock_manager {
+       struct list_head list;
+};
+
+void locks_start_grace(struct lock_manager *);
+void locks_end_grace(struct lock_manager *);
+int locks_in_grace(void);
+
 /* that will die - we need it for nfs_lock_info */
 #include <linux/nfs_fs_i.h>
 
 
                                                struct nfs_fh *,
                                                struct file **);
        void                    (*fclose)(struct file *);
-       unsigned long           (*get_grace_period)(void);
 };
 
 extern struct nlmsvc_binding * nlmsvc_ops;
 extern int     lockd_up(int proto);
 extern void    lockd_down(void);
 
-unsigned long get_nfs_grace_period(void);
-
-#ifdef CONFIG_NFSD_V4
-unsigned long get_nfs4_grace_period(void);
-#else
-static inline unsigned long get_nfs4_grace_period(void) {return 0;}
-#endif
-
 #endif /* LINUX_LOCKD_BIND_H */