namespace.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * linux/fs/nfs/namespace.c
  3. *
  4. * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
  5. *
  6. * NFS namespace
  7. */
  8. #include <linux/config.h>
  9. #include <linux/dcache.h>
  10. #include <linux/mount.h>
  11. #include <linux/namei.h>
  12. #include <linux/nfs_fs.h>
  13. #include <linux/string.h>
  14. #include <linux/sunrpc/clnt.h>
  15. #include <linux/vfs.h>
  16. #define NFSDBG_FACILITY NFSDBG_VFS
  17. LIST_HEAD(nfs_automount_list);
  18. static void nfs_expire_automounts(void *list);
  19. static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list);
  20. int nfs_mountpoint_expiry_timeout = 500 * HZ;
  21. /*
  22. * nfs_follow_mountpoint - handle crossing a mountpoint on the server
  23. * @dentry - dentry of mountpoint
  24. * @nd - nameidata info
  25. *
  26. * When we encounter a mountpoint on the server, we want to set up
  27. * a mountpoint on the client too, to prevent inode numbers from
  28. * colliding, and to allow "df" to work properly.
  29. * On NFSv4, we also want to allow for the fact that different
  30. * filesystems may be migrated to different servers in a failover
  31. * situation, and that different filesystems may want to use
  32. * different security flavours.
  33. */
  34. static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
  35. {
  36. struct vfsmount *mnt;
  37. struct nfs_server *server = NFS_SERVER(dentry->d_inode);
  38. struct dentry *parent;
  39. struct nfs_fh fh;
  40. struct nfs_fattr fattr;
  41. int err;
  42. BUG_ON(IS_ROOT(dentry));
  43. dprintk("%s: enter\n", __FUNCTION__);
  44. dput(nd->dentry);
  45. nd->dentry = dget(dentry);
  46. if (d_mountpoint(nd->dentry))
  47. goto out_follow;
  48. /* Look it up again */
  49. parent = dget_parent(nd->dentry);
  50. err = server->rpc_ops->lookup(parent->d_inode, &nd->dentry->d_name, &fh, &fattr);
  51. dput(parent);
  52. if (err != 0)
  53. goto out_err;
  54. if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL)
  55. mnt = nfs_do_refmount(nd->mnt, nd->dentry);
  56. else
  57. mnt = nfs_do_submount(nd->mnt, nd->dentry, &fh, &fattr);
  58. err = PTR_ERR(mnt);
  59. if (IS_ERR(mnt))
  60. goto out_err;
  61. mntget(mnt);
  62. err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list);
  63. if (err < 0) {
  64. mntput(mnt);
  65. if (err == -EBUSY)
  66. goto out_follow;
  67. goto out_err;
  68. }
  69. mntput(nd->mnt);
  70. dput(nd->dentry);
  71. nd->mnt = mnt;
  72. nd->dentry = dget(mnt->mnt_root);
  73. schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
  74. out:
  75. dprintk("%s: done, returned %d\n", __FUNCTION__, err);
  76. return ERR_PTR(err);
  77. out_err:
  78. path_release(nd);
  79. goto out;
  80. out_follow:
  81. while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
  82. ;
  83. err = 0;
  84. goto out;
  85. }
  86. struct inode_operations nfs_mountpoint_inode_operations = {
  87. .follow_link = nfs_follow_mountpoint,
  88. .getattr = nfs_getattr,
  89. };
  90. struct inode_operations nfs_referral_inode_operations = {
  91. .follow_link = nfs_follow_mountpoint,
  92. };
  93. static void nfs_expire_automounts(void *data)
  94. {
  95. struct list_head *list = (struct list_head *)data;
  96. mark_mounts_for_expiry(list);
  97. if (!list_empty(list))
  98. schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
  99. }
  100. void nfs_release_automount_timer(void)
  101. {
  102. if (list_empty(&nfs_automount_list)) {
  103. cancel_delayed_work(&nfs_automount_task);
  104. flush_scheduled_work();
  105. }
  106. }