Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5 1046 lines 24 kB view raw
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 <linux/file.h> 36#include <linux/slab.h> 37#include <linux/namei.h> 38#include <linux/crypto.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 net *, time_t); 62}; 63 64/* Globals */ 65static struct file *rec_file; 66static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; 67static struct nfsd4_client_tracking_ops *client_tracking_ops; 68 69static int 70nfs4_save_creds(const struct cred **original_creds) 71{ 72 struct cred *new; 73 74 new = prepare_creds(); 75 if (!new) 76 return -ENOMEM; 77 78 new->fsuid = 0; 79 new->fsgid = 0; 80 *original_creds = override_creds(new); 81 put_cred(new); 82 return 0; 83} 84 85static void 86nfs4_reset_creds(const struct cred *original) 87{ 88 revert_creds(original); 89} 90 91static void 92md5_to_hex(char *out, char *md5) 93{ 94 int i; 95 96 for (i=0; i<16; i++) { 97 unsigned char c = md5[i]; 98 99 *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); 100 *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); 101 } 102 *out = '\0'; 103} 104 105__be32 106nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) 107{ 108 struct xdr_netobj cksum; 109 struct hash_desc desc; 110 struct scatterlist sg; 111 __be32 status = nfserr_jukebox; 112 113 dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", 114 clname->len, clname->data); 115 desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; 116 desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); 117 if (IS_ERR(desc.tfm)) 118 goto out_no_tfm; 119 cksum.len = crypto_hash_digestsize(desc.tfm); 120 cksum.data = kmalloc(cksum.len, GFP_KERNEL); 121 if (cksum.data == NULL) 122 goto out; 123 124 sg_init_one(&sg, clname->data, clname->len); 125 126 if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data)) 127 goto out; 128 129 md5_to_hex(dname, cksum.data); 130 131 status = nfs_ok; 132out: 133 kfree(cksum.data); 134 crypto_free_hash(desc.tfm); 135out_no_tfm: 136 return status; 137} 138 139static void 140nfsd4_create_clid_dir(struct nfs4_client *clp) 141{ 142 const struct cred *original_cred; 143 char *dname = clp->cl_recdir; 144 struct dentry *dir, *dentry; 145 int status; 146 147 dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); 148 149 if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 150 return; 151 if (!rec_file) 152 return; 153 status = nfs4_save_creds(&original_cred); 154 if (status < 0) 155 return; 156 157 dir = rec_file->f_path.dentry; 158 /* lock the parent */ 159 mutex_lock(&dir->d_inode->i_mutex); 160 161 dentry = lookup_one_len(dname, dir, HEXDIR_LEN-1); 162 if (IS_ERR(dentry)) { 163 status = PTR_ERR(dentry); 164 goto out_unlock; 165 } 166 if (dentry->d_inode) 167 /* 168 * In the 4.1 case, where we're called from 169 * reclaim_complete(), records from the previous reboot 170 * may still be left, so this is OK. 171 * 172 * In the 4.0 case, we should never get here; but we may 173 * as well be forgiving and just succeed silently. 174 */ 175 goto out_put; 176 status = mnt_want_write_file(rec_file); 177 if (status) 178 goto out_put; 179 status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); 180 mnt_drop_write_file(rec_file); 181out_put: 182 dput(dentry); 183out_unlock: 184 mutex_unlock(&dir->d_inode->i_mutex); 185 if (status == 0) 186 vfs_fsync(rec_file, 0); 187 else 188 printk(KERN_ERR "NFSD: failed to write recovery record" 189 " (err %d); please check that %s exists" 190 " and is writeable", status, 191 user_recovery_dirname); 192 nfs4_reset_creds(original_cred); 193} 194 195typedef int (recdir_func)(struct dentry *, struct dentry *); 196 197struct name_list { 198 char name[HEXDIR_LEN]; 199 struct list_head list; 200}; 201 202static int 203nfsd4_build_namelist(void *arg, const char *name, int namlen, 204 loff_t offset, u64 ino, unsigned int d_type) 205{ 206 struct list_head *names = arg; 207 struct name_list *entry; 208 209 if (namlen != HEXDIR_LEN - 1) 210 return 0; 211 entry = kmalloc(sizeof(struct name_list), GFP_KERNEL); 212 if (entry == NULL) 213 return -ENOMEM; 214 memcpy(entry->name, name, HEXDIR_LEN - 1); 215 entry->name[HEXDIR_LEN - 1] = '\0'; 216 list_add(&entry->list, names); 217 return 0; 218} 219 220static int 221nfsd4_list_rec_dir(recdir_func *f) 222{ 223 const struct cred *original_cred; 224 struct dentry *dir = rec_file->f_path.dentry; 225 LIST_HEAD(names); 226 int status; 227 228 status = nfs4_save_creds(&original_cred); 229 if (status < 0) 230 return status; 231 232 status = vfs_llseek(rec_file, 0, SEEK_SET); 233 if (status < 0) { 234 nfs4_reset_creds(original_cred); 235 return status; 236 } 237 238 status = vfs_readdir(rec_file, nfsd4_build_namelist, &names); 239 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); 240 while (!list_empty(&names)) { 241 struct name_list *entry; 242 entry = list_entry(names.next, struct name_list, list); 243 if (!status) { 244 struct dentry *dentry; 245 dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); 246 if (IS_ERR(dentry)) { 247 status = PTR_ERR(dentry); 248 break; 249 } 250 status = f(dir, dentry); 251 dput(dentry); 252 } 253 list_del(&entry->list); 254 kfree(entry); 255 } 256 mutex_unlock(&dir->d_inode->i_mutex); 257 nfs4_reset_creds(original_cred); 258 return status; 259} 260 261static int 262nfsd4_unlink_clid_dir(char *name, int namlen) 263{ 264 struct dentry *dir, *dentry; 265 int status; 266 267 dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); 268 269 dir = rec_file->f_path.dentry; 270 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); 271 dentry = lookup_one_len(name, dir, namlen); 272 if (IS_ERR(dentry)) { 273 status = PTR_ERR(dentry); 274 goto out_unlock; 275 } 276 status = -ENOENT; 277 if (!dentry->d_inode) 278 goto out; 279 status = vfs_rmdir(dir->d_inode, dentry); 280out: 281 dput(dentry); 282out_unlock: 283 mutex_unlock(&dir->d_inode->i_mutex); 284 return status; 285} 286 287static void 288nfsd4_remove_clid_dir(struct nfs4_client *clp) 289{ 290 const struct cred *original_cred; 291 int status; 292 293 if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 294 return; 295 296 status = mnt_want_write_file(rec_file); 297 if (status) 298 goto out; 299 clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 300 301 status = nfs4_save_creds(&original_cred); 302 if (status < 0) 303 goto out; 304 305 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); 306 nfs4_reset_creds(original_cred); 307 if (status == 0) 308 vfs_fsync(rec_file, 0); 309 mnt_drop_write_file(rec_file); 310out: 311 if (status) 312 printk("NFSD: Failed to remove expired client state directory" 313 " %.*s\n", HEXDIR_LEN, clp->cl_recdir); 314} 315 316static int 317purge_old(struct dentry *parent, struct dentry *child) 318{ 319 int status; 320 321 if (nfs4_has_reclaimed_state(child->d_name.name, false)) 322 return 0; 323 324 status = vfs_rmdir(parent->d_inode, child); 325 if (status) 326 printk("failed to remove client recovery directory %s\n", 327 child->d_name.name); 328 /* Keep trying, success or failure: */ 329 return 0; 330} 331 332static void 333nfsd4_recdir_purge_old(struct net *net, time_t boot_time) 334{ 335 int status; 336 337 if (!rec_file) 338 return; 339 status = mnt_want_write_file(rec_file); 340 if (status) 341 goto out; 342 status = nfsd4_list_rec_dir(purge_old); 343 if (status == 0) 344 vfs_fsync(rec_file, 0); 345 mnt_drop_write_file(rec_file); 346out: 347 if (status) 348 printk("nfsd4: failed to purge old clients from recovery" 349 " directory %s\n", rec_file->f_path.dentry->d_name.name); 350} 351 352static int 353load_recdir(struct dentry *parent, struct dentry *child) 354{ 355 if (child->d_name.len != HEXDIR_LEN - 1) { 356 printk("nfsd4: illegal name %s in recovery directory\n", 357 child->d_name.name); 358 /* Keep trying; maybe the others are OK: */ 359 return 0; 360 } 361 nfs4_client_to_reclaim(child->d_name.name); 362 return 0; 363} 364 365static int 366nfsd4_recdir_load(void) { 367 int status; 368 369 if (!rec_file) 370 return 0; 371 372 status = nfsd4_list_rec_dir(load_recdir); 373 if (status) 374 printk("nfsd4: failed loading clients from recovery" 375 " directory %s\n", rec_file->f_path.dentry->d_name.name); 376 return status; 377} 378 379/* 380 * Hold reference to the recovery directory. 381 */ 382 383static int 384nfsd4_init_recdir(void) 385{ 386 const struct cred *original_cred; 387 int status; 388 389 printk("NFSD: Using %s as the NFSv4 state recovery directory\n", 390 user_recovery_dirname); 391 392 BUG_ON(rec_file); 393 394 status = nfs4_save_creds(&original_cred); 395 if (status < 0) { 396 printk("NFSD: Unable to change credentials to find recovery" 397 " directory: error %d\n", 398 status); 399 return status; 400 } 401 402 rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); 403 if (IS_ERR(rec_file)) { 404 printk("NFSD: unable to find recovery directory %s\n", 405 user_recovery_dirname); 406 status = PTR_ERR(rec_file); 407 rec_file = NULL; 408 } 409 410 nfs4_reset_creds(original_cred); 411 return status; 412} 413 414static int 415nfsd4_load_reboot_recovery_data(struct net *net) 416{ 417 int status; 418 419 /* XXX: The legacy code won't work in a container */ 420 if (net != &init_net) { 421 WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client " 422 "tracking in a container!\n"); 423 return -EINVAL; 424 } 425 426 nfs4_lock_state(); 427 status = nfsd4_init_recdir(); 428 if (!status) 429 status = nfsd4_recdir_load(); 430 nfs4_unlock_state(); 431 if (status) 432 printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); 433 return status; 434} 435 436static void 437nfsd4_shutdown_recdir(void) 438{ 439 if (!rec_file) 440 return; 441 fput(rec_file); 442 rec_file = NULL; 443} 444 445static void 446nfsd4_legacy_tracking_exit(struct net *net) 447{ 448 nfs4_release_reclaim(); 449 nfsd4_shutdown_recdir(); 450} 451 452/* 453 * Change the NFSv4 recovery directory to recdir. 454 */ 455int 456nfs4_reset_recoverydir(char *recdir) 457{ 458 int status; 459 struct path path; 460 461 status = kern_path(recdir, LOOKUP_FOLLOW, &path); 462 if (status) 463 return status; 464 status = -ENOTDIR; 465 if (S_ISDIR(path.dentry->d_inode->i_mode)) { 466 strcpy(user_recovery_dirname, recdir); 467 status = 0; 468 } 469 path_put(&path); 470 return status; 471} 472 473char * 474nfs4_recoverydir(void) 475{ 476 return user_recovery_dirname; 477} 478 479static int 480nfsd4_check_legacy_client(struct nfs4_client *clp) 481{ 482 /* did we already find that this client is stable? */ 483 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 484 return 0; 485 486 /* look for it in the reclaim hashtable otherwise */ 487 if (nfsd4_find_reclaim_client(clp)) { 488 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 489 return 0; 490 } 491 492 return -ENOENT; 493} 494 495static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { 496 .init = nfsd4_load_reboot_recovery_data, 497 .exit = nfsd4_legacy_tracking_exit, 498 .create = nfsd4_create_clid_dir, 499 .remove = nfsd4_remove_clid_dir, 500 .check = nfsd4_check_legacy_client, 501 .grace_done = nfsd4_recdir_purge_old, 502}; 503 504/* Globals */ 505#define NFSD_PIPE_DIR "nfsd" 506#define NFSD_CLD_PIPE "cld" 507 508/* per-net-ns structure for holding cld upcall info */ 509struct cld_net { 510 struct rpc_pipe *cn_pipe; 511 spinlock_t cn_lock; 512 struct list_head cn_list; 513 unsigned int cn_xid; 514}; 515 516struct cld_upcall { 517 struct list_head cu_list; 518 struct cld_net *cu_net; 519 struct task_struct *cu_task; 520 struct cld_msg cu_msg; 521}; 522 523static int 524__cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) 525{ 526 int ret; 527 struct rpc_pipe_msg msg; 528 529 memset(&msg, 0, sizeof(msg)); 530 msg.data = cmsg; 531 msg.len = sizeof(*cmsg); 532 533 /* 534 * Set task state before we queue the upcall. That prevents 535 * wake_up_process in the downcall from racing with schedule. 536 */ 537 set_current_state(TASK_UNINTERRUPTIBLE); 538 ret = rpc_queue_upcall(pipe, &msg); 539 if (ret < 0) { 540 set_current_state(TASK_RUNNING); 541 goto out; 542 } 543 544 schedule(); 545 set_current_state(TASK_RUNNING); 546 547 if (msg.errno < 0) 548 ret = msg.errno; 549out: 550 return ret; 551} 552 553static int 554cld_pipe_upcall(struct rpc_pipe *pipe, struct cld_msg *cmsg) 555{ 556 int ret; 557 558 /* 559 * -EAGAIN occurs when pipe is closed and reopened while there are 560 * upcalls queued. 561 */ 562 do { 563 ret = __cld_pipe_upcall(pipe, cmsg); 564 } while (ret == -EAGAIN); 565 566 return ret; 567} 568 569static ssize_t 570cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) 571{ 572 struct cld_upcall *tmp, *cup; 573 struct cld_msg __user *cmsg = (struct cld_msg __user *)src; 574 uint32_t xid; 575 struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info, 576 nfsd_net_id); 577 struct cld_net *cn = nn->cld_net; 578 579 if (mlen != sizeof(*cmsg)) { 580 dprintk("%s: got %zu bytes, expected %zu\n", __func__, mlen, 581 sizeof(*cmsg)); 582 return -EINVAL; 583 } 584 585 /* copy just the xid so we can try to find that */ 586 if (copy_from_user(&xid, &cmsg->cm_xid, sizeof(xid)) != 0) { 587 dprintk("%s: error when copying xid from userspace", __func__); 588 return -EFAULT; 589 } 590 591 /* walk the list and find corresponding xid */ 592 cup = NULL; 593 spin_lock(&cn->cn_lock); 594 list_for_each_entry(tmp, &cn->cn_list, cu_list) { 595 if (get_unaligned(&tmp->cu_msg.cm_xid) == xid) { 596 cup = tmp; 597 list_del_init(&cup->cu_list); 598 break; 599 } 600 } 601 spin_unlock(&cn->cn_lock); 602 603 /* couldn't find upcall? */ 604 if (!cup) { 605 dprintk("%s: couldn't find upcall -- xid=%u\n", __func__, xid); 606 return -EINVAL; 607 } 608 609 if (copy_from_user(&cup->cu_msg, src, mlen) != 0) 610 return -EFAULT; 611 612 wake_up_process(cup->cu_task); 613 return mlen; 614} 615 616static void 617cld_pipe_destroy_msg(struct rpc_pipe_msg *msg) 618{ 619 struct cld_msg *cmsg = msg->data; 620 struct cld_upcall *cup = container_of(cmsg, struct cld_upcall, 621 cu_msg); 622 623 /* errno >= 0 means we got a downcall */ 624 if (msg->errno >= 0) 625 return; 626 627 wake_up_process(cup->cu_task); 628} 629 630static const struct rpc_pipe_ops cld_upcall_ops = { 631 .upcall = rpc_pipe_generic_upcall, 632 .downcall = cld_pipe_downcall, 633 .destroy_msg = cld_pipe_destroy_msg, 634}; 635 636static struct dentry * 637nfsd4_cld_register_sb(struct super_block *sb, struct rpc_pipe *pipe) 638{ 639 struct dentry *dir, *dentry; 640 641 dir = rpc_d_lookup_sb(sb, NFSD_PIPE_DIR); 642 if (dir == NULL) 643 return ERR_PTR(-ENOENT); 644 dentry = rpc_mkpipe_dentry(dir, NFSD_CLD_PIPE, NULL, pipe); 645 dput(dir); 646 return dentry; 647} 648 649static void 650nfsd4_cld_unregister_sb(struct rpc_pipe *pipe) 651{ 652 if (pipe->dentry) 653 rpc_unlink(pipe->dentry); 654} 655 656static struct dentry * 657nfsd4_cld_register_net(struct net *net, struct rpc_pipe *pipe) 658{ 659 struct super_block *sb; 660 struct dentry *dentry; 661 662 sb = rpc_get_sb_net(net); 663 if (!sb) 664 return NULL; 665 dentry = nfsd4_cld_register_sb(sb, pipe); 666 rpc_put_sb_net(net); 667 return dentry; 668} 669 670static void 671nfsd4_cld_unregister_net(struct net *net, struct rpc_pipe *pipe) 672{ 673 struct super_block *sb; 674 675 sb = rpc_get_sb_net(net); 676 if (sb) { 677 nfsd4_cld_unregister_sb(pipe); 678 rpc_put_sb_net(net); 679 } 680} 681 682/* Initialize rpc_pipefs pipe for communication with client tracking daemon */ 683static int 684nfsd4_init_cld_pipe(struct net *net) 685{ 686 int ret; 687 struct dentry *dentry; 688 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 689 struct cld_net *cn; 690 691 if (nn->cld_net) 692 return 0; 693 694 cn = kzalloc(sizeof(*cn), GFP_KERNEL); 695 if (!cn) { 696 ret = -ENOMEM; 697 goto err; 698 } 699 700 cn->cn_pipe = rpc_mkpipe_data(&cld_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); 701 if (IS_ERR(cn->cn_pipe)) { 702 ret = PTR_ERR(cn->cn_pipe); 703 goto err; 704 } 705 spin_lock_init(&cn->cn_lock); 706 INIT_LIST_HEAD(&cn->cn_list); 707 708 dentry = nfsd4_cld_register_net(net, cn->cn_pipe); 709 if (IS_ERR(dentry)) { 710 ret = PTR_ERR(dentry); 711 goto err_destroy_data; 712 } 713 714 cn->cn_pipe->dentry = dentry; 715 nn->cld_net = cn; 716 return 0; 717 718err_destroy_data: 719 rpc_destroy_pipe_data(cn->cn_pipe); 720err: 721 kfree(cn); 722 printk(KERN_ERR "NFSD: unable to create nfsdcld upcall pipe (%d)\n", 723 ret); 724 return ret; 725} 726 727static void 728nfsd4_remove_cld_pipe(struct net *net) 729{ 730 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 731 struct cld_net *cn = nn->cld_net; 732 733 nfsd4_cld_unregister_net(net, cn->cn_pipe); 734 rpc_destroy_pipe_data(cn->cn_pipe); 735 kfree(nn->cld_net); 736 nn->cld_net = NULL; 737} 738 739static struct cld_upcall * 740alloc_cld_upcall(struct cld_net *cn) 741{ 742 struct cld_upcall *new, *tmp; 743 744 new = kzalloc(sizeof(*new), GFP_KERNEL); 745 if (!new) 746 return new; 747 748 /* FIXME: hard cap on number in flight? */ 749restart_search: 750 spin_lock(&cn->cn_lock); 751 list_for_each_entry(tmp, &cn->cn_list, cu_list) { 752 if (tmp->cu_msg.cm_xid == cn->cn_xid) { 753 cn->cn_xid++; 754 spin_unlock(&cn->cn_lock); 755 goto restart_search; 756 } 757 } 758 new->cu_task = current; 759 new->cu_msg.cm_vers = CLD_UPCALL_VERSION; 760 put_unaligned(cn->cn_xid++, &new->cu_msg.cm_xid); 761 new->cu_net = cn; 762 list_add(&new->cu_list, &cn->cn_list); 763 spin_unlock(&cn->cn_lock); 764 765 dprintk("%s: allocated xid %u\n", __func__, new->cu_msg.cm_xid); 766 767 return new; 768} 769 770static void 771free_cld_upcall(struct cld_upcall *victim) 772{ 773 struct cld_net *cn = victim->cu_net; 774 775 spin_lock(&cn->cn_lock); 776 list_del(&victim->cu_list); 777 spin_unlock(&cn->cn_lock); 778 kfree(victim); 779} 780 781/* Ask daemon to create a new record */ 782static void 783nfsd4_cld_create(struct nfs4_client *clp) 784{ 785 int ret; 786 struct cld_upcall *cup; 787 /* FIXME: determine net from clp */ 788 struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); 789 struct cld_net *cn = nn->cld_net; 790 791 /* Don't upcall if it's already stored */ 792 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 793 return; 794 795 cup = alloc_cld_upcall(cn); 796 if (!cup) { 797 ret = -ENOMEM; 798 goto out_err; 799 } 800 801 cup->cu_msg.cm_cmd = Cld_Create; 802 cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; 803 memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, 804 clp->cl_name.len); 805 806 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 807 if (!ret) { 808 ret = cup->cu_msg.cm_status; 809 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 810 } 811 812 free_cld_upcall(cup); 813out_err: 814 if (ret) 815 printk(KERN_ERR "NFSD: Unable to create client " 816 "record on stable storage: %d\n", ret); 817} 818 819/* Ask daemon to create a new record */ 820static void 821nfsd4_cld_remove(struct nfs4_client *clp) 822{ 823 int ret; 824 struct cld_upcall *cup; 825 /* FIXME: determine net from clp */ 826 struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); 827 struct cld_net *cn = nn->cld_net; 828 829 /* Don't upcall if it's already removed */ 830 if (!test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 831 return; 832 833 cup = alloc_cld_upcall(cn); 834 if (!cup) { 835 ret = -ENOMEM; 836 goto out_err; 837 } 838 839 cup->cu_msg.cm_cmd = Cld_Remove; 840 cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; 841 memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, 842 clp->cl_name.len); 843 844 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 845 if (!ret) { 846 ret = cup->cu_msg.cm_status; 847 clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 848 } 849 850 free_cld_upcall(cup); 851out_err: 852 if (ret) 853 printk(KERN_ERR "NFSD: Unable to remove client " 854 "record from stable storage: %d\n", ret); 855} 856 857/* Check for presence of a record, and update its timestamp */ 858static int 859nfsd4_cld_check(struct nfs4_client *clp) 860{ 861 int ret; 862 struct cld_upcall *cup; 863 /* FIXME: determine net from clp */ 864 struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); 865 struct cld_net *cn = nn->cld_net; 866 867 /* Don't upcall if one was already stored during this grace pd */ 868 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) 869 return 0; 870 871 cup = alloc_cld_upcall(cn); 872 if (!cup) { 873 printk(KERN_ERR "NFSD: Unable to check client record on " 874 "stable storage: %d\n", -ENOMEM); 875 return -ENOMEM; 876 } 877 878 cup->cu_msg.cm_cmd = Cld_Check; 879 cup->cu_msg.cm_u.cm_name.cn_len = clp->cl_name.len; 880 memcpy(cup->cu_msg.cm_u.cm_name.cn_id, clp->cl_name.data, 881 clp->cl_name.len); 882 883 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 884 if (!ret) { 885 ret = cup->cu_msg.cm_status; 886 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 887 } 888 889 free_cld_upcall(cup); 890 return ret; 891} 892 893static void 894nfsd4_cld_grace_done(struct net *net, time_t boot_time) 895{ 896 int ret; 897 struct cld_upcall *cup; 898 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 899 struct cld_net *cn = nn->cld_net; 900 901 cup = alloc_cld_upcall(cn); 902 if (!cup) { 903 ret = -ENOMEM; 904 goto out_err; 905 } 906 907 cup->cu_msg.cm_cmd = Cld_GraceDone; 908 cup->cu_msg.cm_u.cm_gracetime = (int64_t)boot_time; 909 ret = cld_pipe_upcall(cn->cn_pipe, &cup->cu_msg); 910 if (!ret) 911 ret = cup->cu_msg.cm_status; 912 913 free_cld_upcall(cup); 914out_err: 915 if (ret) 916 printk(KERN_ERR "NFSD: Unable to end grace period: %d\n", ret); 917} 918 919static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = { 920 .init = nfsd4_init_cld_pipe, 921 .exit = nfsd4_remove_cld_pipe, 922 .create = nfsd4_cld_create, 923 .remove = nfsd4_cld_remove, 924 .check = nfsd4_cld_check, 925 .grace_done = nfsd4_cld_grace_done, 926}; 927 928int 929nfsd4_client_tracking_init(struct net *net) 930{ 931 int status; 932 struct path path; 933 934 if (!client_tracking_ops) { 935 client_tracking_ops = &nfsd4_cld_tracking_ops; 936 status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path); 937 if (!status) { 938 if (S_ISDIR(path.dentry->d_inode->i_mode)) 939 client_tracking_ops = 940 &nfsd4_legacy_tracking_ops; 941 path_put(&path); 942 } 943 } 944 945 status = client_tracking_ops->init(net); 946 if (status) { 947 printk(KERN_WARNING "NFSD: Unable to initialize client " 948 "recovery tracking! (%d)\n", status); 949 client_tracking_ops = NULL; 950 } 951 return status; 952} 953 954void 955nfsd4_client_tracking_exit(struct net *net) 956{ 957 if (client_tracking_ops) { 958 client_tracking_ops->exit(net); 959 client_tracking_ops = NULL; 960 } 961} 962 963void 964nfsd4_client_record_create(struct nfs4_client *clp) 965{ 966 if (client_tracking_ops) 967 client_tracking_ops->create(clp); 968} 969 970void 971nfsd4_client_record_remove(struct nfs4_client *clp) 972{ 973 if (client_tracking_ops) 974 client_tracking_ops->remove(clp); 975} 976 977int 978nfsd4_client_record_check(struct nfs4_client *clp) 979{ 980 if (client_tracking_ops) 981 return client_tracking_ops->check(clp); 982 983 return -EOPNOTSUPP; 984} 985 986void 987nfsd4_record_grace_done(struct net *net, time_t boot_time) 988{ 989 if (client_tracking_ops) 990 client_tracking_ops->grace_done(net, boot_time); 991} 992 993static int 994rpc_pipefs_event(struct notifier_block *nb, unsigned long event, void *ptr) 995{ 996 struct super_block *sb = ptr; 997 struct net *net = sb->s_fs_info; 998 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 999 struct cld_net *cn = nn->cld_net; 1000 struct dentry *dentry; 1001 int ret = 0; 1002 1003 if (!try_module_get(THIS_MODULE)) 1004 return 0; 1005 1006 if (!cn) { 1007 module_put(THIS_MODULE); 1008 return 0; 1009 } 1010 1011 switch (event) { 1012 case RPC_PIPEFS_MOUNT: 1013 dentry = nfsd4_cld_register_sb(sb, cn->cn_pipe); 1014 if (IS_ERR(dentry)) { 1015 ret = PTR_ERR(dentry); 1016 break; 1017 } 1018 cn->cn_pipe->dentry = dentry; 1019 break; 1020 case RPC_PIPEFS_UMOUNT: 1021 if (cn->cn_pipe->dentry) 1022 nfsd4_cld_unregister_sb(cn->cn_pipe); 1023 break; 1024 default: 1025 ret = -ENOTSUPP; 1026 break; 1027 } 1028 module_put(THIS_MODULE); 1029 return ret; 1030} 1031 1032static struct notifier_block nfsd4_cld_block = { 1033 .notifier_call = rpc_pipefs_event, 1034}; 1035 1036int 1037register_cld_notifier(void) 1038{ 1039 return rpc_pipefs_notifier_register(&nfsd4_cld_block); 1040} 1041 1042void 1043unregister_cld_notifier(void) 1044{ 1045 rpc_pipefs_notifier_unregister(&nfsd4_cld_block); 1046}