linux/fs/nfsd/nfs4recover.c
<<
>>
Prefs
   1/*
   2*  Copyright (c) 2004 The Regents of the University of Michigan.
   3*  Copyright (c) 2012 Jeff Layton <jlayton@redhat.com>
   4*  All rights reserved.
   5*
   6*  Andy Adamson <andros@citi.umich.edu>
   7*
   8*  Redistribution and use in source and binary forms, with or without
   9*  modification, are permitted provided that the following conditions
  10*  are met:
  11*
  12*  1. Redistributions of source code must retain the above copyright
  13*     notice, this list of conditions and the following disclaimer.
  14*  2. Redistributions in binary form must reproduce the above copyright
  15*     notice, this list of conditions and the following disclaimer in the
  16*     documentation and/or other materials provided with the distribution.
  17*  3. Neither the name of the University nor the names of its
  18*     contributors may be used to endorse or promote products derived
  19*     from this software without specific prior written permission.
  20*
  21*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  22*  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  23*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  24*  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25*  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  28*  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29*  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32*
  33*/
  34
  35#include <crypto/hash.h>
  36#include <linux/file.h>
  37#include <linux/slab.h>
  38#include <linux/namei.h>
  39#include <linux/sched.h>
  40#include <linux/fs.h>
  41#include <linux/module.h>
  42#include <net/net_namespace.h>
  43#include <linux/sunrpc/rpc_pipe_fs.h>
  44#include <linux/sunrpc/clnt.h>
  45#include <linux/nfsd/cld.h>
  46
  47#include "nfsd.h"
  48#include "state.h"
  49#include "vfs.h"
  50#include "netns.h"
  51
  52#define NFSDDBG_FACILITY                NFSDDBG_PROC
  53
  54/* Declarations */
  55struct nfsd4_client_tracking_ops {
  56        int (*init)(struct net *);
  57        void (*exit)(struct net *);
  58        void (*create)(struct nfs4_client *);
  59        void (*remove)(struct nfs4_client *);
  60        int (*check)(struct nfs4_client *);
  61        void (*grace_done)(struct nfsd_net *);
  62};
  63
  64/* Globals */
  65static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
  66
  67static int
  68nfs4_save_creds(const struct cred **original_creds)
  69{
  70        struct cred *new;
  71
  72        new = prepare_creds();
  73        if (!new)
  74                return -ENOMEM;
  75
  76        new->fsuid = GLOBAL_ROOT_UID;
  77        new->fsgid = GLOBAL_ROOT_GID;
  78        *original_creds = override_creds(new);
  79        put_cred(new);
  80        return 0;
  81}
  82
  83static void
  84nfs4_reset_creds(const struct cred *original)
  85{
  86        revert_creds(original);
  87}
  88
  89static void
  90md5_to_hex(char *out, char *md5)
  91{
  92        int i;
  93
  94        for (i=0; i<16; i++) {
  95                unsigned char c = md5[i];
  96
  97                *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
  98                *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
  99        }
 100        *out = '\0';
 101}
 102
 103static int
 104nfs4_make_rec_clidname(char *dname, const struct xdr_netobj *clname)
 105{
 106        struct xdr_netobj cksum;
 107        struct crypto_shash *tfm;
 108        int status;
 109
 110        dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
 111                        clname->len, clname->data);
 112        tfm = crypto_alloc_shash("md5", 0, 0);
 113        if (IS_ERR(tfm)) {
 114                status = PTR_ERR(tfm);
 115                goto out_no_tfm;
 116        }
 117
 118        cksum.len = crypto_shash_digestsize(tfm);
 119        cksum.data = kmalloc(cksum.len, GFP_KERNEL);
 120        if (cksum.data == NULL) {
 121                status = -ENOMEM;
 122                goto out;
 123        }
 124
 125        {
 126                SHASH_DESC_ON_STACK(desc, tfm);
 127
 128                desc->tfm = tfm;
 129                desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 130
 131                status = crypto_shash_digest(desc, clname->data, clname->len,
 132                                             cksum.data);
 133                shash_desc_zero(desc);
 134        }
 135
 136        if (status)
 137                goto out;
 138
 139        md5_to_hex(dname, cksum.data);
 140
 141        status = 0;
 142out:
 143        kfree(cksum.data);
 144        crypto_free_shash(tfm);
 145out_no_tfm:
 146        return status;
 147}
 148
 149/*
 150 * If we had an error generating the recdir name for the legacy tracker
 151 * then warn the admin. If the error doesn't appear to be transient,
 152 * then disable recovery tracking.
 153 */
 154static void
 155legacy_recdir_name_error(struct nfs4_client *clp, int error)
 156{
 157        printk(KERN_ERR "NFSD: unable to generate recoverydir "
 158                        "name (%d).\n", error);
 159
 160        /*
 161         * if the algorithm just doesn't exist, then disable the recovery
 162         * tracker altogether. The crypto libs will generally return this if
 163         * FIPS is enabled as well.
 164         */
 165        if (error == -ENOENT) {
 166                printk(KERN_ERR "NFSD: disabling legacy clientid tracking. "
 167                        "Reboot recovery will not function correctly!\n");
 168                nfsd4_client_tracking_exit(clp->net);
 169        }
 170}
 171
 172static void
 173nfsd4_create_clid_dir(struct nfs4_client *clp)
 174{
 175        const struct cred *original_cred;
 176        char dname[HEXDIR_LEN];
 177        struct dentry *dir, *dentry;
 178        struct nfs4_client_reclaim *crp;
 179        int status;
 180        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 181
 182        if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
 183                return;
 184        if (!nn->rec_file)
 185                return;
 186
 187        status = nfs4_make_rec_clidname(dname, &clp->cl_name);
 188        if (status)
 189                return legacy_recdir_name_error(clp, status);
 190
 191        status = nfs4_save_creds(&original_cred);
 192        if (status < 0)
 193                return;
 194
 195        status = mnt_want_write_file(nn->rec_file);
 196        if (status)
 197                goto out_creds;
 198
 199        dir = nn->rec_file->f_path.dentry;
 200        /* lock the parent */
 201        inode_lock(d_inode(dir));
 202
 203        dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1);
 204        if (IS_ERR(dentry)) {
 205                status = PTR_ERR(dentry);
 206                goto out_unlock;
 207        }
 208        if (d_really_is_positive(dentry))
 209                /*
 210                 * In the 4.1 case, where we're called from
 211                 * reclaim_complete(), records from the previous reboot
 212                 * may still be left, so this is OK.
 213                 *
 214                 * In the 4.0 case, we should never get here; but we may
 215                 * as well be forgiving and just succeed silently.
 216                 */
 217                goto out_put;
 218        status = vfs_mkdir(d_inode(dir), dentry, S_IRWXU);
 219out_put:
 220        dput(dentry);
 221out_unlock:
 222        inode_unlock(d_inode(dir));
 223        if (status == 0) {
 224                if (nn->in_grace) {
 225                        crp = nfs4_client_to_reclaim(dname, nn);
 226                        if (crp)
 227                                crp->cr_clp = clp;
 228                }
 229                vfs_fsync(nn->rec_file, 0);
 230        } else {
 231                printk(KERN_ERR "NFSD: failed to write recovery record"
 232                                " (err %d); please check that %s exists"
 233                                " and is writeable", status,
 234                                user_recovery_dirname);
 235        }
 236        mnt_drop_write_file(nn->rec_file);
 237out_creds:
 238        nfs4_reset_creds(original_cred);
 239}
 240
 241typedef int (recdir_func)(struct dentry *, struct dentry *, struct nfsd_net *);
 242
 243struct name_list {
 244        char name[HEXDIR_LEN];
 245        struct list_head list;
 246};
 247
 248struct nfs4_dir_ctx {
 249        struct dir_context ctx;
 250        struct list_head names;
 251};
 252
 253static int
 254nfsd4_build_namelist(struct dir_context *__ctx, const char *name, int namlen,
 255                loff_t offset, u64 ino, unsigned int d_type)
 256{
 257        struct nfs4_dir_ctx *ctx =
 258                container_of(__ctx, struct nfs4_dir_ctx, ctx);
 259        struct name_list *entry;
 260
 261        if (namlen != HEXDIR_LEN - 1)
 262                return 0;
 263        entry = kmalloc(sizeof(struct name_list), GFP_KERNEL);
 264        if (entry == NULL)
 265                return -ENOMEM;
 266        memcpy(entry->name, name, HEXDIR_LEN - 1);
 267        entry->name[HEXDIR_LEN - 1] = '\0';
 268        list_add(&entry->list, &ctx->names);
 269        return 0;
 270}
 271
 272static int
 273nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
 274{
 275        const struct cred *original_cred;
 276        struct dentry *dir = nn->rec_file->f_path.dentry;
 277        struct nfs4_dir_ctx ctx = {
 278                .ctx.actor = nfsd4_build_namelist,
 279                .names = LIST_HEAD_INIT(ctx.names)
 280        };
 281        struct name_list *entry, *tmp;
 282        int status;
 283
 284        status = nfs4_save_creds(&original_cred);
 285        if (status < 0)
 286                return status;
 287
 288        status = vfs_llseek(nn->rec_file, 0, SEEK_SET);
 289        if (status < 0) {
 290                nfs4_reset_creds(original_cred);
 291                return status;
 292        }
 293
 294        status = iterate_dir(nn->rec_file, &ctx.ctx);
 295        inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
 296
 297        list_for_each_entry_safe(entry, tmp, &ctx.names, list) {
 298                if (!status) {
 299                        struct dentry *dentry;
 300                        dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
 301                        if (IS_ERR(dentry)) {
 302                                status = PTR_ERR(dentry);
 303                                break;
 304                        }
 305                        status = f(dir, dentry, nn);
 306                        dput(dentry);
 307                }
 308                list_del(&entry->list);
 309                kfree(entry);
 310        }
 311        inode_unlock(d_inode(dir));
 312        nfs4_reset_creds(original_cred);
 313
 314        list_for_each_entry_safe(entry, tmp, &ctx.names, list) {
 315                dprintk("NFSD: %s. Left entry %s\n", __func__, entry->name);
 316                list_del(&entry->list);
 317                kfree(entry);
 318        }
 319        return status;
 320}
 321
 322static int
 323nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn)
 324{
 325        struct dentry *dir, *dentry;
 326        int status;
 327
 328        dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
 329
 330        dir = nn->rec_file->f_path.dentry;
 331        inode_lock_nested(d_inode(dir), I_MUTEX_PARENT);
 332        dentry = lookup_one_len(name, dir, namlen);
 333        if (IS_ERR(dentry)) {
 334                status = PTR_ERR(dentry);
 335                goto out_unlock;
 336        }
 337        status = -ENOENT;
 338        if (d_really_is_negative(dentry))
 339                goto out;
 340        status = vfs_rmdir(d_inode(dir), dentry);
 341out:
 342        dput(dentry);
 343out_unlock:
 344        inode_unlock(d_inode(dir));
 345        return status;
 346}
 347
 348static void
 349nfsd4_remove_clid_dir(struct nfs4_client *clp)
 350{
 351        const struct cred *original_cred;
 352        struct nfs4_client_reclaim *crp;
 353        char dname[HEXDIR_LEN];
 354        int status;
 355        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 356
 357        if (!nn->rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
 358                return;
 359
 360        status = nfs4_make_rec_clidname(dname, &clp->cl_name);
 361        if (status)
 362                return legacy_recdir_name_error(clp, status);
 363
 364        status = mnt_want_write_file(nn->rec_file);
 365        if (status)
 366                goto out;
 367        clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
 368
 369        status = nfs4_save_creds(&original_cred);
 370        if (status < 0)
 371                goto out_drop_write;
 372
 373        status = nfsd4_unlink_clid_dir(dname, HEXDIR_LEN-1, nn);
 374        nfs4_reset_creds(original_cred);
 375        if (status == 0) {
 376                vfs_fsync(nn->rec_file, 0);
 377                if (nn->in_grace) {
 378                        /* remove reclaim record */
 379                        crp = nfsd4_find_reclaim_client(dname, nn);
 380                        if (crp)
 381                                nfs4_remove_reclaim_record(crp, nn);
 382                }
 383        }
 384out_drop_write:
 385        mnt_drop_write_file(nn->rec_file);
 386out:
 387        if (status)
 388                printk("NFSD: Failed to remove expired client state directory"
 389                                " %.*s\n", HEXDIR_LEN, dname);
 390}
 391
 392static int
 393purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
 394{
 395        int status;
 396
 397        if (nfs4_has_reclaimed_state(child->d_name.name, nn))
 398                return 0;
 399
 400        status = vfs_rmdir(d_inode(parent), child);
 401        if (status)
 402                printk("failed to remove client recovery directory %pd\n",
 403                                child);
 404        /* Keep trying, success or failure: */
 405        return 0;
 406}
 407
 408static void
 409nfsd4_recdir_purge_old(struct nfsd_net *nn)
 410{
 411        int status;
 412
 413        nn->in_grace = false;
 414        if (!nn->rec_file)
 415                return;
 416        status = mnt_want_write_file(nn->rec_file);
 417        if (status)
 418                goto out;
 419        status = nfsd4_list_rec_dir(purge_old, nn);
 420        if (status == 0)
 421                vfs_fsync(nn->rec_file, 0);
 422        mnt_drop_write_file(nn->rec_file);
 423out:
 424        nfs4_release_reclaim(nn);
 425        if (status)
 426                printk("nfsd4: failed to purge old clients from recovery"
 427                        " directory %pD\n", nn->rec_file);
 428}
 429
 430static int
 431load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
 432{
 433        if (child->d_name.len != HEXDIR_LEN - 1) {
 434                printk("nfsd4: illegal name %pd in recovery directory\n",
 435                                child);
 436                /* Keep trying; maybe the others are OK: */
 437                return 0;
 438        }
 439        nfs4_client_to_reclaim(child->d_name.name, nn);
 440        return 0;
 441}
 442
 443static int
 444nfsd4_recdir_load(struct net *net) {
 445        int status;
 446        struct nfsd_net *nn =  net_generic(net, nfsd_net_id);
 447
 448        if (!nn->rec_file)
 449                return 0;
 450
 451        status = nfsd4_list_rec_dir(load_recdir, nn);
 452        if (status)
 453                printk("nfsd4: failed loading clients from recovery"
 454                        " directory %pD\n", nn->rec_file);
 455        return status;
 456}
 457
 458/*
 459 * Hold reference to the recovery directory.
 460 */
 461
 462static int
 463nfsd4_init_recdir(struct net *net)
 464{
 465        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 466        const struct cred *original_cred;
 467        int status;
 468
 469        printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
 470                        user_recovery_dirname);
 471
 472        BUG_ON(nn->rec_file);
 473
 474        status = nfs4_save_creds(&original_cred);
 475        if (status < 0) {
 476                printk("NFSD: Unable to change credentials to find recovery"
 477                       " directory: error %d\n",
 478                       status);
 479                return status;
 480        }
 481
 482        nn->rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
 483        if (IS_ERR(nn->rec_file)) {
 484                printk("NFSD: unable to find recovery directory %s\n",
 485                                user_recovery_dirname);
 486                status = PTR_ERR(nn->rec_file);
 487                nn->rec_file = NULL;
 488        }
 489
 490        nfs4_reset_creds(original_cred);
 491        if (!status)
 492                nn->in_grace = true;
 493        return status;
 494}
 495
 496static void
 497nfsd4_shutdown_recdir(struct net *net)
 498{
 499        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 500
 501        if (!nn->rec_file)
 502                return;
 503        fput(nn->rec_file);
 504        nn->rec_file = NULL;
 505}
 506
 507static int
 508nfs4_legacy_state_init(struct net *net)
 509{
 510        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 511        int i;
 512
 513        nn->reclaim_str_hashtbl = kmalloc(sizeof(struct list_head) *
 514                                          CLIENT_HASH_SIZE, GFP_KERNEL);
 515        if (!nn->reclaim_str_hashtbl)
 516                return -ENOMEM;
 517
 518        for (i = 0; i < CLIENT_HASH_SIZE; i++)
 519                INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]);
 520        nn->reclaim_str_hashtbl_size = 0;
 521
 522        return 0;
 523}
 524
 525static void
 526nfs4_legacy_state_shutdown(struct net *net)
 527{
 528        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 529
 530        kfree(nn->reclaim_str_hashtbl);
 531}
 532
 533static int
 534nfsd4_load_reboot_recovery_data(struct net *net)
 535{
 536        int status;
 537
 538        status = nfsd4_init_recdir(net);
 539        if (status)
 540                return status;
 541
 542        status = nfsd4_recdir_load(net);
 543        if (status)
 544                nfsd4_shutdown_recdir(net);
 545
 546        return status;
 547}
 548
 549static int
 550nfsd4_legacy_tracking_init(struct net *net)
 551{
 552        int status;
 553
 554        /* XXX: The legacy code won't work in a container */
 555        if (net != &init_net) {
 556                pr_warn("NFSD: attempt to initialize legacy client tracking in a container ignored.\n");
 557                return -EINVAL;
 558        }
 559
 560        status = nfs4_legacy_state_init(net);
 561        if (status)
 562                return status;
 563
 564        status = nfsd4_load_reboot_recovery_data(net);
 565        if (status)
 566                goto err;
 567        return 0;
 568
 569err:
 570        nfs4_legacy_state_shutdown(net);
 571        return status;
 572}
 573
 574static void
 575nfsd4_legacy_tracking_exit(struct net *net)
 576{
 577        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 578
 579        nfs4_release_reclaim(nn);
 580        nfsd4_shutdown_recdir(net);
 581        nfs4_legacy_state_shutdown(net);
 582}
 583
 584/*
 585 * Change the NFSv4 recovery directory to recdir.
 586 */
 587int
 588nfs4_reset_recoverydir(char *recdir)
 589{
 590        int status;
 591        struct path path;
 592
 593        status = kern_path(recdir, LOOKUP_FOLLOW, &path);
 594        if (status)
 595                return status;
 596        status = -ENOTDIR;
 597        if (d_is_dir(path.dentry)) {
 598                strcpy(user_recovery_dirname, recdir);
 599                status = 0;
 600        }
 601        path_put(&path);
 602        return status;
 603}
 604
 605char *
 606nfs4_recoverydir(void)
 607{
 608        return user_recovery_dirname;
 609}
 610
 611static int
 612nfsd4_check_legacy_client(struct nfs4_client *clp)
 613{
 614        int status;
 615        char dname[HEXDIR_LEN];
 616        struct nfs4_client_reclaim *crp;
 617        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 618
 619        /* did we already find that this client is stable? */
 620        if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
 621                return 0;
 622
 623        status = nfs4_make_rec_clidname(dname, &clp->cl_name);
 624        if (status) {
 625                legacy_recdir_name_error(clp, status);
 626                return status;
 627        }
 628
 629        /* look for it in the reclaim hashtable otherwise */
 630        crp = nfsd4_find_reclaim_client(dname, nn);
 631        if (crp) {
 632                set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
 633                crp->cr_clp = clp;
 634                return 0;
 635        }
 636
 637        return -ENOENT;
 638}
 639
 640static const struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
 641        .init           = nfsd4_legacy_tracking_init,
 642        .exit           = nfsd4_legacy_tracking_exit,
 643        .create         = nfsd4_create_clid_dir,
 644        .remove         = nfsd4_remove_clid_dir,
 645        .check          = nfsd4_check_legacy_client,
 646        .grace_done     = nfsd4_recdir_purge_old,
 647};
 648
 649/* Globals */
 650#define NFSD_PIPE_DIR           "nfsd"
 651#define NFSD_CLD_PIPE           "cld"
 652
 653/* per-net-ns structure for holding cld upcall info */
 654struct cld_net {
 655        struct rpc_pipe         *cn_pipe;
 656        spinlock_t               cn_lock;
 657        struct list_head         cn_list;
 658        unsigned int             cn_xid;
 659};
 660
 661struct cld_upcall {
 662        struct list_head         cu_list;
 663        struct cld_net          *cu_net;
 664        struct task_struct      *cu_task;
 665        struct cld_msg           cu_msg;
 666};
 667
 668static int
 669__cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
 670{
 671        int ret;
 672        struct rpc_pipe_msg msg;
 673
 674        memset(&msg, 0, sizeof(msg));
 675        msg.data = cmsg;
 676        msg.len = sizeof(*cmsg);
 677
 678        /*
 679         * Set task state before we queue the upcall. That prevents
 680         * wake_up_process in the downcall from racing with schedule.
 681         */
 682        set_current_state(TASK_UNINTERRUPTIBLE);
 683        ret = rpc_queue_upcall(pipe, &msg);
 684        if (ret < 0) {
 685                set_current_state(TASK_RUNNING);
 686                goto out;
 687        }
 688
 689        schedule();
 690
 691        if (msg.errno < 0)
 692                ret = msg.errno;
 693out:
 694        return ret;
 695}
 696
 697static int
 698cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg)
 699{
 700        int ret;
 701
 702        /*
 703         * -EAGAIN occurs when pipe is closed and reopened while there are
 704         *  upcalls queued.
 705         */
 706        do {
 707                ret = __cld_pipe_upcall(pipe, cmsg);
 708        } while (ret == -EAGAIN);
 709
 710        return ret;
 711}
 712
 713static ssize_t
 714cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 715{
 716        struct cld_upcall *tmp, *cup;
 717        struct cld_msg __user *cmsg = (struct cld_msg __user *)src;
 718        uint32_t xid;
 719        struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
 720                                                nfsd_net_id);
 721        struct cld_net *cn = nn->cld_net;
 722
 723        if (mlen != sizeof(*cmsg)) {
 724                dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen,
 725                        sizeof(*cmsg));
 726                return -EINVAL;
 727        }
 728
 729        /* copy just the xid so we can try to find that */
 730        if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) {
 731                dprintk("%s: error when copying xid from userspace", __func__);
 732                return -EFAULT;
 733        }
 734
 735        /* walk the list and find corresponding xid */
 736        cup = NULL;
 737        spin_lock(&cn->cn_lock);
 738        list_for_each_entry(tmp, &cn->cn_list, cu_list) {
 739                if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) {
 740                        cup = tmp;
 741                        list_del_init(&cup->cu_list);
 742                        break;
 743                }
 744        }
 745        spin_unlock(&cn->cn_lock);
 746
 747        /* couldn't find upcall? */
 748        if (!cup) {
 749                dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid);
 750                return -EINVAL;
 751        }
 752
 753        if (copy_from_user(&cup->cu_msg, src, mlen) != 0)
 754                return -EFAULT;
 755
 756        wake_up_process(cup->cu_task);
 757        return mlen;
 758}
 759
 760static void
 761cld_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 762{
 763        struct cld_msg *cmsg = msg->data;
 764        struct cld_upcall *cup = container_of(cmsg, struct cld_upcall,
 765                                                 cu_msg);
 766
 767        /* errno >= 0 means we got a downcall */
 768        if (msg->errno >= 0)
 769                return;
 770
 771        wake_up_process(cup->cu_task);
 772}
 773
 774static const struct rpc_pipe_ops cld_upcall_ops = {
 775        .upcall         = rpc_pipe_generic_upcall,
 776        .downcall       = cld_pipe_downcall,
 777        .destroy_msg    = cld_pipe_destroy_msg,
 778};
 779
 780static struct dentry *
 781nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe)
 782{
 783        struct dentry *dir, *dentry;
 784
 785        dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR);
 786        if (dir == NULL)
 787                return ERR_PTR(-ENOENT);
 788        dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe);
 789        dput(dir);
 790        return dentry;
 791}
 792
 793static void
 794nfsd4_cld_unregister_sb(struct rpc_pipe *pipe)
 795{
 796        if (pipe->dentry)
 797                rpc_unlink(pipe->dentry);
 798}
 799
 800static struct dentry *
 801nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe)
 802{
 803        struct super_block *sb;
 804        struct dentry *dentry;
 805
 806        sb = rpc_get_sb_net(net);
 807        if (!sb)
 808                return NULL;
 809        dentry = nfsd4_cld_register_sb(sb, pipe);
 810        rpc_put_sb_net(net);
 811        return dentry;
 812}
 813
 814static void
 815nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe)
 816{
 817        struct super_block *sb;
 818
 819        sb = rpc_get_sb_net(net);
 820        if (sb) {
 821                nfsd4_cld_unregister_sb(pipe);
 822                rpc_put_sb_net(net);
 823        }
 824}
 825
 826/* Initialize rpc_pipefs pipe for communication with client tracking daemon */
 827static int
 828nfsd4_init_cld_pipe(struct net *net)
 829{
 830        int ret;
 831        struct dentry *dentry;
 832        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 833        struct cld_net *cn;
 834
 835        if (nn->cld_net)
 836                return 0;
 837
 838        cn = kzalloc(sizeof(*cn), GFP_KERNEL);
 839        if (!cn) {
 840                ret = -ENOMEM;
 841                goto err;
 842        }
 843
 844        cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
 845        if (IS_ERR(cn->cn_pipe)) {
 846                ret = PTR_ERR(cn->cn_pipe);
 847                goto err;
 848        }
 849        spin_lock_init(&cn->cn_lock);
 850        INIT_LIST_HEAD(&cn->cn_list);
 851
 852        dentry = nfsd4_cld_register_net(net, cn->cn_pipe);
 853        if (IS_ERR(dentry)) {
 854                ret = PTR_ERR(dentry);
 855                goto err_destroy_data;
 856        }
 857
 858        cn->cn_pipe->dentry = dentry;
 859        nn->cld_net = cn;
 860        return 0;
 861
 862err_destroy_data:
 863        rpc_destroy_pipe_data(cn->cn_pipe);
 864err:
 865        kfree(cn);
 866        printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n",
 867                        ret);
 868        return ret;
 869}
 870
 871static void
 872nfsd4_remove_cld_pipe(struct net *net)
 873{
 874        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 875        struct cld_net *cn = nn->cld_net;
 876
 877        nfsd4_cld_unregister_net(net, cn->cn_pipe);
 878        rpc_destroy_pipe_data(cn->cn_pipe);
 879        kfree(nn->cld_net);
 880        nn->cld_net = NULL;
 881}
 882
 883static struct cld_upcall *
 884alloc_cld_upcall(struct cld_net *cn)
 885{
 886        struct cld_upcall *new, *tmp;
 887
 888        new = kzalloc(sizeof(*new), GFP_KERNEL);
 889        if (!new)
 890                return new;
 891
 892        /* FIXME: hard cap on number in flight? */
 893restart_search:
 894        spin_lock(&cn->cn_lock);
 895        list_for_each_entry(tmp, &cn->cn_list, cu_list) {
 896                if (tmp->cu_msg.cm_xid == cn->cn_xid) {
 897                        cn->cn_xid++;
 898                        spin_unlock(&cn->cn_lock);
 899                        goto restart_search;
 900                }
 901        }
 902        new->cu_task = current;
 903        new->cu_msg.cm_vers = CLD_UPCALL_VERSION;
 904        put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid);
 905        new->cu_net = cn;
 906        list_add(&new->cu_list, &cn->cn_list);
 907        spin_unlock(&cn->cn_lock);
 908
 909        dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid);
 910
 911        return new;
 912}
 913
 914static void
 915free_cld_upcall(struct cld_upcall *victim)
 916{
 917        struct cld_net *cn = victim->cu_net;
 918
 919        spin_lock(&cn->cn_lock);
 920        list_del(&victim->cu_list);
 921        spin_unlock(&cn->cn_lock);
 922        kfree(victim);
 923}
 924
 925/* Ask daemon to create a new record */
 926static void
 927nfsd4_cld_create(struct nfs4_client *clp)
 928{
 929        int ret;
 930        struct cld_upcall *cup;
 931        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 932        struct cld_net *cn = nn->cld_net;
 933
 934        /* Don't upcall if it's already stored */
 935        if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
 936                return;
 937
 938        cup = alloc_cld_upcall(cn);
 939        if (!cup) {
 940                ret = -ENOMEM;
 941                goto out_err;
 942        }
 943
 944        cup->cu_msg.cm_cmd = Cld_Create;
 945        cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
 946        memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
 947                        clp->cl_name.len);
 948
 949        ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
 950        if (!ret) {
 951                ret = cup->cu_msg.cm_status;
 952                set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
 953        }
 954
 955        free_cld_upcall(cup);
 956out_err:
 957        if (ret)
 958                printk(KERN_ERR "NFSD: Unable to create client "
 959                                "record on stable storage: %d\n", ret);
 960}
 961
 962/* Ask daemon to create a new record */
 963static void
 964nfsd4_cld_remove(struct nfs4_client *clp)
 965{
 966        int ret;
 967        struct cld_upcall *cup;
 968        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 969        struct cld_net *cn = nn->cld_net;
 970
 971        /* Don't upcall if it's already removed */
 972        if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
 973                return;
 974
 975        cup = alloc_cld_upcall(cn);
 976        if (!cup) {
 977                ret = -ENOMEM;
 978                goto out_err;
 979        }
 980
 981        cup->cu_msg.cm_cmd = Cld_Remove;
 982        cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
 983        memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
 984                        clp->cl_name.len);
 985
 986        ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
 987        if (!ret) {
 988                ret = cup->cu_msg.cm_status;
 989                clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
 990        }
 991
 992        free_cld_upcall(cup);
 993out_err:
 994        if (ret)
 995                printk(KERN_ERR "NFSD: Unable to remove client "
 996                                "record from stable storage: %d\n", ret);
 997}
 998
 999/* Check for presence of a record, and update its timestamp */
1000static int
1001nfsd4_cld_check(struct nfs4_client *clp)
1002{
1003        int ret;
1004        struct cld_upcall *cup;
1005        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1006        struct cld_net *cn = nn->cld_net;
1007
1008        /* Don't upcall if one was already stored during this grace pd */
1009        if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1010                return 0;
1011
1012        cup = alloc_cld_upcall(cn);
1013        if (!cup) {
1014                printk(KERN_ERR "NFSD: Unable to check client record on "
1015                                "stable storage: %d\n", -ENOMEM);
1016                return -ENOMEM;
1017        }
1018
1019        cup->cu_msg.cm_cmd = Cld_Check;
1020        cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len;
1021        memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data,
1022                        clp->cl_name.len);
1023
1024        ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
1025        if (!ret) {
1026                ret = cup->cu_msg.cm_status;
1027                set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1028        }
1029
1030        free_cld_upcall(cup);
1031        return ret;
1032}
1033
1034static void
1035nfsd4_cld_grace_done(struct nfsd_net *nn)
1036{
1037        int ret;
1038        struct cld_upcall *cup;
1039        struct cld_net *cn = nn->cld_net;
1040
1041        cup = alloc_cld_upcall(cn);
1042        if (!cup) {
1043                ret = -ENOMEM;
1044                goto out_err;
1045        }
1046
1047        cup->cu_msg.cm_cmd = Cld_GraceDone;
1048        cup->cu_msg.cm_u.cm_gracetime = (int64_t)nn->boot_time;
1049        ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg);
1050        if (!ret)
1051                ret = cup->cu_msg.cm_status;
1052
1053        free_cld_upcall(cup);
1054out_err:
1055        if (ret)
1056                printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret);
1057}
1058
1059static const struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
1060        .init           = nfsd4_init_cld_pipe,
1061        .exit           = nfsd4_remove_cld_pipe,
1062        .create         = nfsd4_cld_create,
1063        .remove         = nfsd4_cld_remove,
1064        .check          = nfsd4_cld_check,
1065        .grace_done     = nfsd4_cld_grace_done,
1066};
1067
1068/* upcall via usermodehelper */
1069static char cltrack_prog[PATH_MAX] = "/sbin/nfsdcltrack";
1070module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog),
1071                        S_IRUGO|S_IWUSR);
1072MODULE_PARM_DESC(cltrack_prog, "Path to the nfsdcltrack upcall program");
1073
1074static bool cltrack_legacy_disable;
1075module_param(cltrack_legacy_disable, bool, S_IRUGO|S_IWUSR);
1076MODULE_PARM_DESC(cltrack_legacy_disable,
1077                "Disable legacy recoverydir conversion. Default: false");
1078
1079#define LEGACY_TOPDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_TOPDIR="
1080#define LEGACY_RECDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_RECDIR="
1081#define HAS_SESSION_ENV_PREFIX "NFSDCLTRACK_CLIENT_HAS_SESSION="
1082#define GRACE_START_ENV_PREFIX "NFSDCLTRACK_GRACE_START="
1083
1084static char *
1085nfsd4_cltrack_legacy_topdir(void)
1086{
1087        int copied;
1088        size_t len;
1089        char *result;
1090
1091        if (cltrack_legacy_disable)
1092                return NULL;
1093
1094        len = strlen(LEGACY_TOPDIR_ENV_PREFIX) +
1095                strlen(nfs4_recoverydir()) + 1;
1096
1097        result = kmalloc(len, GFP_KERNEL);
1098        if (!result)
1099                return result;
1100
1101        copied = snprintf(result, len, LEGACY_TOPDIR_ENV_PREFIX "%s",
1102                                nfs4_recoverydir());
1103        if (copied >= len) {
1104                /* just return nothing if output was truncated */
1105                kfree(result);
1106                return NULL;
1107        }
1108
1109        return result;
1110}
1111
1112static char *
1113nfsd4_cltrack_legacy_recdir(const struct xdr_netobj *name)
1114{
1115        int copied;
1116        size_t len;
1117        char *result;
1118
1119        if (cltrack_legacy_disable)
1120                return NULL;
1121
1122        /* +1 is for '/' between "topdir" and "recdir" */
1123        len = strlen(LEGACY_RECDIR_ENV_PREFIX) +
1124                strlen(nfs4_recoverydir()) + 1 + HEXDIR_LEN;
1125
1126        result = kmalloc(len, GFP_KERNEL);
1127        if (!result)
1128                return result;
1129
1130        copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/",
1131                                nfs4_recoverydir());
1132        if (copied > (len - HEXDIR_LEN)) {
1133                /* just return nothing if output will be truncated */
1134                kfree(result);
1135                return NULL;
1136        }
1137
1138        copied = nfs4_make_rec_clidname(result + copied, name);
1139        if (copied) {
1140                kfree(result);
1141                return NULL;
1142        }
1143
1144        return result;
1145}
1146
1147static char *
1148nfsd4_cltrack_client_has_session(struct nfs4_client *clp)
1149{
1150        int copied;
1151        size_t len;
1152        char *result;
1153
1154        /* prefix + Y/N character + terminating NULL */
1155        len = strlen(HAS_SESSION_ENV_PREFIX) + 1 + 1;
1156
1157        result = kmalloc(len, GFP_KERNEL);
1158        if (!result)
1159                return result;
1160
1161        copied = snprintf(result, len, HAS_SESSION_ENV_PREFIX "%c",
1162                                clp->cl_minorversion ? 'Y' : 'N');
1163        if (copied >= len) {
1164                /* just return nothing if output was truncated */
1165                kfree(result);
1166                return NULL;
1167        }
1168
1169        return result;
1170}
1171
1172static char *
1173nfsd4_cltrack_grace_start(time_t grace_start)
1174{
1175        int copied;
1176        size_t len;
1177        char *result;
1178
1179        /* prefix + max width of int64_t string + terminating NULL */
1180        len = strlen(GRACE_START_ENV_PREFIX) + 22 + 1;
1181
1182        result = kmalloc(len, GFP_KERNEL);
1183        if (!result)
1184                return result;
1185
1186        copied = snprintf(result, len, GRACE_START_ENV_PREFIX "%ld",
1187                                grace_start);
1188        if (copied >= len) {
1189                /* just return nothing if output was truncated */
1190                kfree(result);
1191                return NULL;
1192        }
1193
1194        return result;
1195}
1196
1197static int
1198nfsd4_umh_cltrack_upcall(char *cmd, char *arg, char *env0, char *env1)
1199{
1200        char *envp[3];
1201        char *argv[4];
1202        int ret;
1203
1204        if (unlikely(!cltrack_prog[0])) {
1205                dprintk("%s: cltrack_prog is disabled\n", __func__);
1206                return -EACCES;
1207        }
1208
1209        dprintk("%s: cmd: %s\n", __func__, cmd);
1210        dprintk("%s: arg: %s\n", __func__, arg ? arg : "(null)");
1211        dprintk("%s: env0: %s\n", __func__, env0 ? env0 : "(null)");
1212        dprintk("%s: env1: %s\n", __func__, env1 ? env1 : "(null)");
1213
1214        envp[0] = env0;
1215        envp[1] = env1;
1216        envp[2] = NULL;
1217
1218        argv[0] = (char *)cltrack_prog;
1219        argv[1] = cmd;
1220        argv[2] = arg;
1221        argv[3] = NULL;
1222
1223        ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
1224        /*
1225         * Disable the upcall mechanism if we're getting an ENOENT or EACCES
1226         * error. The admin can re-enable it on the fly by using sysfs
1227         * once the problem has been fixed.
1228         */
1229        if (ret == -ENOENT || ret == -EACCES) {
1230                dprintk("NFSD: %s was not found or isn't executable (%d). "
1231                        "Setting cltrack_prog to blank string!",
1232                        cltrack_prog, ret);
1233                cltrack_prog[0] = '\0';
1234        }
1235        dprintk("%s: %s return value: %d\n", __func__, cltrack_prog, ret);
1236
1237        return ret;
1238}
1239
1240static char *
1241bin_to_hex_dup(const unsigned char *src, int srclen)
1242{
1243        int i;
1244        char *buf, *hex;
1245
1246        /* +1 for terminating NULL */
1247        buf = kmalloc((srclen * 2) + 1, GFP_KERNEL);
1248        if (!buf)
1249                return buf;
1250
1251        hex = buf;
1252        for (i = 0; i < srclen; i++) {
1253                sprintf(hex, "%2.2x", *src++);
1254                hex += 2;
1255        }
1256        return buf;
1257}
1258
1259static int
1260nfsd4_umh_cltrack_init(struct net *net)
1261{
1262        int ret;
1263        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1264        char *grace_start = nfsd4_cltrack_grace_start(nn->boot_time);
1265
1266        /* XXX: The usermode helper s not working in container yet. */
1267        if (net != &init_net) {
1268                pr_warn("NFSD: attempt to initialize umh client tracking in a container ignored.\n");
1269                kfree(grace_start);
1270                return -EINVAL;
1271        }
1272
1273        ret = nfsd4_umh_cltrack_upcall("init", NULL, grace_start, NULL);
1274        kfree(grace_start);
1275        return ret;
1276}
1277
1278static void
1279nfsd4_cltrack_upcall_lock(struct nfs4_client *clp)
1280{
1281        wait_on_bit_lock(&clp->cl_flags, NFSD4_CLIENT_UPCALL_LOCK,
1282                         TASK_UNINTERRUPTIBLE);
1283}
1284
1285static void
1286nfsd4_cltrack_upcall_unlock(struct nfs4_client *clp)
1287{
1288        smp_mb__before_atomic();
1289        clear_bit(NFSD4_CLIENT_UPCALL_LOCK, &clp->cl_flags);
1290        smp_mb__after_atomic();
1291        wake_up_bit(&clp->cl_flags, NFSD4_CLIENT_UPCALL_LOCK);
1292}
1293
1294static void
1295nfsd4_umh_cltrack_create(struct nfs4_client *clp)
1296{
1297        char *hexid, *has_session, *grace_start;
1298        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1299
1300        /*
1301         * With v4.0 clients, there's little difference in outcome between a
1302         * create and check operation, and we can end up calling into this
1303         * function multiple times per client (once for each openowner). So,
1304         * for v4.0 clients skip upcalling once the client has been recorded
1305         * on stable storage.
1306         *
1307         * For v4.1+ clients, the outcome of the two operations is different,
1308         * so we must ensure that we upcall for the create operation. v4.1+
1309         * clients call this on RECLAIM_COMPLETE though, so we should only end
1310         * up doing a single create upcall per client.
1311         */
1312        if (clp->cl_minorversion == 0 &&
1313            test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1314                return;
1315
1316        hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1317        if (!hexid) {
1318                dprintk("%s: can't allocate memory for upcall!\n", __func__);
1319                return;
1320        }
1321
1322        has_session = nfsd4_cltrack_client_has_session(clp);
1323        grace_start = nfsd4_cltrack_grace_start(nn->boot_time);
1324
1325        nfsd4_cltrack_upcall_lock(clp);
1326        if (!nfsd4_umh_cltrack_upcall("create", hexid, has_session, grace_start))
1327                set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1328        nfsd4_cltrack_upcall_unlock(clp);
1329
1330        kfree(has_session);
1331        kfree(grace_start);
1332        kfree(hexid);
1333}
1334
1335static void
1336nfsd4_umh_cltrack_remove(struct nfs4_client *clp)
1337{
1338        char *hexid;
1339
1340        if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1341                return;
1342
1343        hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1344        if (!hexid) {
1345                dprintk("%s: can't allocate memory for upcall!\n", __func__);
1346                return;
1347        }
1348
1349        nfsd4_cltrack_upcall_lock(clp);
1350        if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags) &&
1351            nfsd4_umh_cltrack_upcall("remove", hexid, NULL, NULL) == 0)
1352                clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1353        nfsd4_cltrack_upcall_unlock(clp);
1354
1355        kfree(hexid);
1356}
1357
1358static int
1359nfsd4_umh_cltrack_check(struct nfs4_client *clp)
1360{
1361        int ret;
1362        char *hexid, *has_session, *legacy;
1363
1364        if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
1365                return 0;
1366
1367        hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
1368        if (!hexid) {
1369                dprintk("%s: can't allocate memory for upcall!\n", __func__);
1370                return -ENOMEM;
1371        }
1372
1373        has_session = nfsd4_cltrack_client_has_session(clp);
1374        legacy = nfsd4_cltrack_legacy_recdir(&clp->cl_name);
1375
1376        nfsd4_cltrack_upcall_lock(clp);
1377        if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) {
1378                ret = 0;
1379        } else {
1380                ret = nfsd4_umh_cltrack_upcall("check", hexid, has_session, legacy);
1381                if (ret == 0)
1382                        set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
1383        }
1384        nfsd4_cltrack_upcall_unlock(clp);
1385        kfree(has_session);
1386        kfree(legacy);
1387        kfree(hexid);
1388
1389        return ret;
1390}
1391
1392static void
1393nfsd4_umh_cltrack_grace_done(struct nfsd_net *nn)
1394{
1395        char *legacy;
1396        char timestr[22]; /* FIXME: better way to determine max size? */
1397
1398        sprintf(timestr, "%ld", nn->boot_time);
1399        legacy = nfsd4_cltrack_legacy_topdir();
1400        nfsd4_umh_cltrack_upcall("gracedone", timestr, legacy, NULL);
1401        kfree(legacy);
1402}
1403
1404static const struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
1405        .init           = nfsd4_umh_cltrack_init,
1406        .exit           = NULL,
1407        .create         = nfsd4_umh_cltrack_create,
1408        .remove         = nfsd4_umh_cltrack_remove,
1409        .check          = nfsd4_umh_cltrack_check,
1410        .grace_done     = nfsd4_umh_cltrack_grace_done,
1411};
1412
1413int
1414nfsd4_client_tracking_init(struct net *net)
1415{
1416        int status;
1417        struct path path;
1418        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1419
1420        /* just run the init if it the method is already decided */
1421        if (nn->client_tracking_ops)
1422                goto do_init;
1423
1424        /*
1425         * First, try a UMH upcall. It should succeed or fail quickly, so
1426         * there's little harm in trying that first.
1427         */
1428        nn->client_tracking_ops = &nfsd4_umh_tracking_ops;
1429        status = nn->client_tracking_ops->init(net);
1430        if (!status)
1431                return status;
1432
1433        /*
1434         * See if the recoverydir exists and is a directory. If it is,
1435         * then use the legacy ops.
1436         */
1437        nn->client_tracking_ops = &nfsd4_legacy_tracking_ops;
1438        status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
1439        if (!status) {
1440                status = d_is_dir(path.dentry);
1441                path_put(&path);
1442                if (status)
1443                        goto do_init;
1444        }
1445
1446        /* Finally, try to use nfsdcld */
1447        nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
1448        printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be "
1449                        "removed in 3.10. Please transition to using "
1450                        "nfsdcltrack.\n");
1451do_init:
1452        status = nn->client_tracking_ops->init(net);
1453        if (status) {
1454                printk(KERN_WARNING "NFSD: Unable to initialize client "
1455                                    "recovery tracking! (%d)\n", status);
1456                nn->client_tracking_ops = NULL;
1457        }
1458        return status;
1459}
1460
1461void
1462nfsd4_client_tracking_exit(struct net *net)
1463{
1464        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1465
1466        if (nn->client_tracking_ops) {
1467                if (nn->client_tracking_ops->exit)
1468                        nn->client_tracking_ops->exit(net);
1469                nn->client_tracking_ops = NULL;
1470        }
1471}
1472
1473void
1474nfsd4_client_record_create(struct nfs4_client *clp)
1475{
1476        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1477
1478        if (nn->client_tracking_ops)
1479                nn->client_tracking_ops->create(clp);
1480}
1481
1482void
1483nfsd4_client_record_remove(struct nfs4_client *clp)
1484{
1485        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1486
1487        if (nn->client_tracking_ops)
1488                nn->client_tracking_ops->remove(clp);
1489}
1490
1491int
1492nfsd4_client_record_check(struct nfs4_client *clp)
1493{
1494        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1495
1496        if (nn->client_tracking_ops)
1497                return nn->client_tracking_ops->check(clp);
1498
1499        return -EOPNOTSUPP;
1500}
1501
1502void
1503nfsd4_record_grace_done(struct nfsd_net *nn)
1504{
1505        if (nn->client_tracking_ops)
1506                nn->client_tracking_ops->grace_done(nn);
1507}
1508
1509static int
1510rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr)
1511{
1512        struct super_block *sb = ptr;
1513        struct net *net = sb->s_fs_info;
1514        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1515        struct cld_net *cn = nn->cld_net;
1516        struct dentry *dentry;
1517        int ret = 0;
1518
1519        if (!try_module_get(THIS_MODULE))
1520                return 0;
1521
1522        if (!cn) {
1523                module_put(THIS_MODULE);
1524                return 0;
1525        }
1526
1527        switch (event) {
1528        case RPC_PIPEFS_MOUNT:
1529                dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe);
1530                if (IS_ERR(dentry)) {
1531                        ret = PTR_ERR(dentry);
1532                        break;
1533                }
1534                cn->cn_pipe->dentry = dentry;
1535                break;
1536        case RPC_PIPEFS_UMOUNT:
1537                if (cn->cn_pipe->dentry)
1538                        nfsd4_cld_unregister_sb(cn->cn_pipe);
1539                break;
1540        default:
1541                ret = -ENOTSUPP;
1542                break;
1543        }
1544        module_put(THIS_MODULE);
1545        return ret;
1546}
1547
1548static struct notifier_block nfsd4_cld_block = {
1549        .notifier_call = rpc_pipefs_event,
1550};
1551
1552int
1553register_cld_notifier(void)
1554{
1555        return rpc_pipefs_notifier_register(&nfsd4_cld_block);
1556}
1557
1558void
1559unregister_cld_notifier(void)
1560{
1561        rpc_pipefs_notifier_unregister(&nfsd4_cld_block);
1562}
1563