nfs4super.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * Copyright (c) 2012 Bryan Schumaker <bjschuma@netapp.com>
  3. */
  4. #include <linux/init.h>
  5. #include <linux/module.h>
  6. #include <linux/nfs_idmap.h>
  7. #include <linux/nfs4_mount.h>
  8. #include <linux/nfs_fs.h>
  9. #include "internal.h"
  10. #include "nfs4_fs.h"
  11. #include "nfs.h"
  12. #define NFSDBG_FACILITY NFSDBG_VFS
  13. static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
  14. int flags, const char *dev_name, void *raw_data);
  15. static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
  16. int flags, const char *dev_name, void *raw_data);
  17. static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
  18. int flags, const char *dev_name, void *raw_data);
  19. static struct file_system_type nfs4_fs_type = {
  20. .owner = THIS_MODULE,
  21. .name = "nfs4",
  22. .mount = nfs_fs_mount,
  23. .kill_sb = nfs_kill_super,
  24. .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
  25. };
  26. static struct file_system_type nfs4_remote_fs_type = {
  27. .owner = THIS_MODULE,
  28. .name = "nfs4",
  29. .mount = nfs4_remote_mount,
  30. .kill_sb = nfs_kill_super,
  31. .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
  32. };
  33. static struct file_system_type nfs4_remote_referral_fs_type = {
  34. .owner = THIS_MODULE,
  35. .name = "nfs4",
  36. .mount = nfs4_remote_referral_mount,
  37. .kill_sb = nfs_kill_super,
  38. .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
  39. };
  40. struct file_system_type nfs4_referral_fs_type = {
  41. .owner = THIS_MODULE,
  42. .name = "nfs4",
  43. .mount = nfs4_referral_mount,
  44. .kill_sb = nfs_kill_super,
  45. .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
  46. };
  47. static const struct super_operations nfs4_sops = {
  48. .alloc_inode = nfs_alloc_inode,
  49. .destroy_inode = nfs_destroy_inode,
  50. .write_inode = nfs4_write_inode,
  51. .put_super = nfs_put_super,
  52. .statfs = nfs_statfs,
  53. .evict_inode = nfs4_evict_inode,
  54. .umount_begin = nfs_umount_begin,
  55. .show_options = nfs_show_options,
  56. .show_devname = nfs_show_devname,
  57. .show_path = nfs_show_path,
  58. .show_stats = nfs_show_stats,
  59. .remount_fs = nfs_remount,
  60. };
  61. struct nfs_subversion nfs_v4 = {
  62. .owner = THIS_MODULE,
  63. .nfs_fs = &nfs4_fs_type,
  64. .rpc_vers = &nfs_version4,
  65. .rpc_ops = &nfs_v4_clientops,
  66. };
  67. /*
  68. * Set up an NFS4 superblock
  69. */
  70. static void nfs4_fill_super(struct super_block *sb,
  71. struct nfs_mount_info *mount_info)
  72. {
  73. sb->s_time_gran = 1;
  74. sb->s_op = &nfs4_sops;
  75. /*
  76. * The VFS shouldn't apply the umask to mode bits. We will do
  77. * so ourselves when necessary.
  78. */
  79. sb->s_flags |= MS_POSIXACL;
  80. sb->s_xattr = nfs4_xattr_handlers;
  81. nfs_initialise_sb(sb);
  82. }
  83. /*
  84. * Get the superblock for the NFS4 root partition
  85. */
  86. static struct dentry *
  87. nfs4_remote_mount(struct file_system_type *fs_type, int flags,
  88. const char *dev_name, void *info)
  89. {
  90. struct nfs_mount_info *mount_info = info;
  91. struct nfs_server *server;
  92. struct dentry *mntroot = ERR_PTR(-ENOMEM);
  93. mount_info->fill_super = nfs4_fill_super;
  94. mount_info->set_security = nfs_set_sb_security;
  95. /* Get a volume representation */
  96. server = nfs4_create_server(mount_info->parsed, mount_info->mntfh);
  97. if (IS_ERR(server)) {
  98. mntroot = ERR_CAST(server);
  99. goto out;
  100. }
  101. mntroot = nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4);
  102. out:
  103. return mntroot;
  104. }
  105. static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
  106. int flags, void *data, const char *hostname)
  107. {
  108. struct vfsmount *root_mnt;
  109. char *root_devname;
  110. size_t len;
  111. len = strlen(hostname) + 5;
  112. root_devname = kmalloc(len, GFP_KERNEL);
  113. if (root_devname == NULL)
  114. return ERR_PTR(-ENOMEM);
  115. /* Does hostname needs to be enclosed in brackets? */
  116. if (strchr(hostname, ':'))
  117. snprintf(root_devname, len, "[%s]:/", hostname);
  118. else
  119. snprintf(root_devname, len, "%s:/", hostname);
  120. root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
  121. kfree(root_devname);
  122. return root_mnt;
  123. }
  124. struct nfs_referral_count {
  125. struct list_head list;
  126. const struct task_struct *task;
  127. unsigned int referral_count;
  128. };
  129. static LIST_HEAD(nfs_referral_count_list);
  130. static DEFINE_SPINLOCK(nfs_referral_count_list_lock);
  131. static struct nfs_referral_count *nfs_find_referral_count(void)
  132. {
  133. struct nfs_referral_count *p;
  134. list_for_each_entry(p, &nfs_referral_count_list, list) {
  135. if (p->task == current)
  136. return p;
  137. }
  138. return NULL;
  139. }
  140. #define NFS_MAX_NESTED_REFERRALS 2
  141. static int nfs_referral_loop_protect(void)
  142. {
  143. struct nfs_referral_count *p, *new;
  144. int ret = -ENOMEM;
  145. new = kmalloc(sizeof(*new), GFP_KERNEL);
  146. if (!new)
  147. goto out;
  148. new->task = current;
  149. new->referral_count = 1;
  150. ret = 0;
  151. spin_lock(&nfs_referral_count_list_lock);
  152. p = nfs_find_referral_count();
  153. if (p != NULL) {
  154. if (p->referral_count >= NFS_MAX_NESTED_REFERRALS)
  155. ret = -ELOOP;
  156. else
  157. p->referral_count++;
  158. } else {
  159. list_add(&new->list, &nfs_referral_count_list);
  160. new = NULL;
  161. }
  162. spin_unlock(&nfs_referral_count_list_lock);
  163. kfree(new);
  164. out:
  165. return ret;
  166. }
  167. static void nfs_referral_loop_unprotect(void)
  168. {
  169. struct nfs_referral_count *p;
  170. spin_lock(&nfs_referral_count_list_lock);
  171. p = nfs_find_referral_count();
  172. p->referral_count--;
  173. if (p->referral_count == 0)
  174. list_del(&p->list);
  175. else
  176. p = NULL;
  177. spin_unlock(&nfs_referral_count_list_lock);
  178. kfree(p);
  179. }
  180. static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
  181. const char *export_path)
  182. {
  183. struct dentry *dentry;
  184. int err;
  185. if (IS_ERR(root_mnt))
  186. return ERR_CAST(root_mnt);
  187. err = nfs_referral_loop_protect();
  188. if (err) {
  189. mntput(root_mnt);
  190. return ERR_PTR(err);
  191. }
  192. dentry = mount_subtree(root_mnt, export_path);
  193. nfs_referral_loop_unprotect();
  194. return dentry;
  195. }
  196. struct dentry *nfs4_try_mount(int flags, const char *dev_name,
  197. struct nfs_mount_info *mount_info,
  198. struct nfs_subversion *nfs_mod)
  199. {
  200. char *export_path;
  201. struct vfsmount *root_mnt;
  202. struct dentry *res;
  203. struct nfs_parsed_mount_data *data = mount_info->parsed;
  204. dfprintk(MOUNT, "--> nfs4_try_mount()\n");
  205. mount_info->fill_super = nfs4_fill_super;
  206. export_path = data->nfs_server.export_path;
  207. data->nfs_server.export_path = "/";
  208. root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
  209. data->nfs_server.hostname);
  210. data->nfs_server.export_path = export_path;
  211. res = nfs_follow_remote_path(root_mnt, export_path);
  212. dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n",
  213. IS_ERR(res) ? PTR_ERR(res) : 0,
  214. IS_ERR(res) ? " [error]" : "");
  215. return res;
  216. }
  217. static struct dentry *
  218. nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
  219. const char *dev_name, void *raw_data)
  220. {
  221. struct nfs_mount_info mount_info = {
  222. .fill_super = nfs4_fill_super,
  223. .set_security = nfs_clone_sb_security,
  224. .cloned = raw_data,
  225. };
  226. struct nfs_server *server;
  227. struct dentry *mntroot = ERR_PTR(-ENOMEM);
  228. dprintk("--> nfs4_referral_get_sb()\n");
  229. mount_info.mntfh = nfs_alloc_fhandle();
  230. if (mount_info.cloned == NULL || mount_info.mntfh == NULL)
  231. goto out;
  232. /* create a new volume representation */
  233. server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
  234. if (IS_ERR(server)) {
  235. mntroot = ERR_CAST(server);
  236. goto out;
  237. }
  238. mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, &nfs_v4);
  239. out:
  240. nfs_free_fhandle(mount_info.mntfh);
  241. return mntroot;
  242. }
  243. /*
  244. * Create an NFS4 server record on referral traversal
  245. */
  246. static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
  247. int flags, const char *dev_name, void *raw_data)
  248. {
  249. struct nfs_clone_mount *data = raw_data;
  250. char *export_path;
  251. struct vfsmount *root_mnt;
  252. struct dentry *res;
  253. dprintk("--> nfs4_referral_mount()\n");
  254. export_path = data->mnt_path;
  255. data->mnt_path = "/";
  256. root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
  257. flags, data, data->hostname);
  258. data->mnt_path = export_path;
  259. res = nfs_follow_remote_path(root_mnt, export_path);
  260. dprintk("<-- nfs4_referral_mount() = %ld%s\n",
  261. IS_ERR(res) ? PTR_ERR(res) : 0,
  262. IS_ERR(res) ? " [error]" : "");
  263. return res;
  264. }
  265. int __init init_nfs_v4(void)
  266. {
  267. int err;
  268. err = nfs_idmap_init();
  269. if (err)
  270. goto out;
  271. err = nfs4_register_sysctl();
  272. if (err)
  273. goto out1;
  274. err = register_filesystem(&nfs4_fs_type);
  275. if (err < 0)
  276. goto out2;
  277. register_nfs_version(&nfs_v4);
  278. return 0;
  279. out2:
  280. nfs4_unregister_sysctl();
  281. out1:
  282. nfs_idmap_quit();
  283. out:
  284. return err;
  285. }
  286. void exit_nfs_v4(void)
  287. {
  288. unregister_nfs_version(&nfs_v4);
  289. unregister_filesystem(&nfs4_fs_type);
  290. nfs4_unregister_sysctl();
  291. nfs_idmap_quit();
  292. }