2 * Copyright (c) 2012 Bryan Schumaker <bjschuma@netapp.com>
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>
13 #define NFSDBG_FACILITY NFSDBG_VFS
15 static struct dentry
*nfs4_remote_mount(struct file_system_type
*fs_type
,
16 int flags
, const char *dev_name
, void *raw_data
);
17 static struct dentry
*nfs4_xdev_mount(struct file_system_type
*fs_type
,
18 int flags
, const char *dev_name
, void *raw_data
);
19 static struct dentry
*nfs4_referral_mount(struct file_system_type
*fs_type
,
20 int flags
, const char *dev_name
, void *raw_data
);
21 static struct dentry
*nfs4_remote_referral_mount(struct file_system_type
*fs_type
,
22 int flags
, const char *dev_name
, void *raw_data
);
24 static struct file_system_type nfs4_fs_type
= {
27 .mount
= nfs_fs_mount
,
28 .kill_sb
= nfs_kill_super
,
29 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
32 static struct file_system_type nfs4_remote_fs_type
= {
35 .mount
= nfs4_remote_mount
,
36 .kill_sb
= nfs_kill_super
,
37 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
40 struct file_system_type nfs4_xdev_fs_type
= {
43 .mount
= nfs4_xdev_mount
,
44 .kill_sb
= nfs_kill_super
,
45 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
48 static struct file_system_type nfs4_remote_referral_fs_type
= {
51 .mount
= nfs4_remote_referral_mount
,
52 .kill_sb
= nfs_kill_super
,
53 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
56 struct file_system_type nfs4_referral_fs_type
= {
59 .mount
= nfs4_referral_mount
,
60 .kill_sb
= nfs_kill_super
,
61 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
64 static const struct super_operations nfs4_sops
= {
65 .alloc_inode
= nfs_alloc_inode
,
66 .destroy_inode
= nfs_destroy_inode
,
67 .write_inode
= nfs4_write_inode
,
68 .put_super
= nfs_put_super
,
70 .evict_inode
= nfs4_evict_inode
,
71 .umount_begin
= nfs_umount_begin
,
72 .show_options
= nfs_show_options
,
73 .show_devname
= nfs_show_devname
,
74 .show_path
= nfs_show_path
,
75 .show_stats
= nfs_show_stats
,
76 .remount_fs
= nfs_remount
,
79 struct nfs_subversion nfs_v4
= {
81 .nfs_fs
= &nfs4_fs_type
,
82 .rpc_vers
= &nfs_version4
,
83 .rpc_ops
= &nfs_v4_clientops
,
87 * Set up an NFS4 superblock
89 static void nfs4_fill_super(struct super_block
*sb
,
90 struct nfs_mount_info
*mount_info
)
93 sb
->s_op
= &nfs4_sops
;
95 * The VFS shouldn't apply the umask to mode bits. We will do
96 * so ourselves when necessary.
98 sb
->s_flags
|= MS_POSIXACL
;
99 sb
->s_xattr
= nfs4_xattr_handlers
;
100 nfs_initialise_sb(sb
);
104 * Get the superblock for the NFS4 root partition
106 static struct dentry
*
107 nfs4_remote_mount(struct file_system_type
*fs_type
, int flags
,
108 const char *dev_name
, void *info
)
110 struct nfs_mount_info
*mount_info
= info
;
111 struct nfs_server
*server
;
112 struct dentry
*mntroot
= ERR_PTR(-ENOMEM
);
114 mount_info
->fill_super
= nfs4_fill_super
;
115 mount_info
->set_security
= nfs_set_sb_security
;
117 /* Get a volume representation */
118 server
= nfs4_create_server(mount_info
->parsed
, mount_info
->mntfh
);
119 if (IS_ERR(server
)) {
120 mntroot
= ERR_CAST(server
);
124 mntroot
= nfs_fs_mount_common(server
, flags
, dev_name
, mount_info
, &nfs_v4
);
130 static struct vfsmount
*nfs_do_root_mount(struct file_system_type
*fs_type
,
131 int flags
, void *data
, const char *hostname
)
133 struct vfsmount
*root_mnt
;
137 len
= strlen(hostname
) + 5;
138 root_devname
= kmalloc(len
, GFP_KERNEL
);
139 if (root_devname
== NULL
)
140 return ERR_PTR(-ENOMEM
);
141 /* Does hostname needs to be enclosed in brackets? */
142 if (strchr(hostname
, ':'))
143 snprintf(root_devname
, len
, "[%s]:/", hostname
);
145 snprintf(root_devname
, len
, "%s:/", hostname
);
146 root_mnt
= vfs_kern_mount(fs_type
, flags
, root_devname
, data
);
151 struct nfs_referral_count
{
152 struct list_head list
;
153 const struct task_struct
*task
;
154 unsigned int referral_count
;
157 static LIST_HEAD(nfs_referral_count_list
);
158 static DEFINE_SPINLOCK(nfs_referral_count_list_lock
);
160 static struct nfs_referral_count
*nfs_find_referral_count(void)
162 struct nfs_referral_count
*p
;
164 list_for_each_entry(p
, &nfs_referral_count_list
, list
) {
165 if (p
->task
== current
)
171 #define NFS_MAX_NESTED_REFERRALS 2
173 static int nfs_referral_loop_protect(void)
175 struct nfs_referral_count
*p
, *new;
178 new = kmalloc(sizeof(*new), GFP_KERNEL
);
182 new->referral_count
= 1;
185 spin_lock(&nfs_referral_count_list_lock
);
186 p
= nfs_find_referral_count();
188 if (p
->referral_count
>= NFS_MAX_NESTED_REFERRALS
)
193 list_add(&new->list
, &nfs_referral_count_list
);
196 spin_unlock(&nfs_referral_count_list_lock
);
202 static void nfs_referral_loop_unprotect(void)
204 struct nfs_referral_count
*p
;
206 spin_lock(&nfs_referral_count_list_lock
);
207 p
= nfs_find_referral_count();
209 if (p
->referral_count
== 0)
213 spin_unlock(&nfs_referral_count_list_lock
);
217 static struct dentry
*nfs_follow_remote_path(struct vfsmount
*root_mnt
,
218 const char *export_path
)
220 struct dentry
*dentry
;
223 if (IS_ERR(root_mnt
))
224 return ERR_CAST(root_mnt
);
226 err
= nfs_referral_loop_protect();
232 dentry
= mount_subtree(root_mnt
, export_path
);
233 nfs_referral_loop_unprotect();
238 struct dentry
*nfs4_try_mount(int flags
, const char *dev_name
,
239 struct nfs_mount_info
*mount_info
)
242 struct vfsmount
*root_mnt
;
244 struct nfs_parsed_mount_data
*data
= mount_info
->parsed
;
246 dfprintk(MOUNT
, "--> nfs4_try_mount()\n");
248 mount_info
->fill_super
= nfs4_fill_super
;
250 export_path
= data
->nfs_server
.export_path
;
251 data
->nfs_server
.export_path
= "/";
252 root_mnt
= nfs_do_root_mount(&nfs4_remote_fs_type
, flags
, mount_info
,
253 data
->nfs_server
.hostname
);
254 data
->nfs_server
.export_path
= export_path
;
256 res
= nfs_follow_remote_path(root_mnt
, export_path
);
258 dfprintk(MOUNT
, "<-- nfs4_try_mount() = %ld%s\n",
259 IS_ERR(res
) ? PTR_ERR(res
) : 0,
260 IS_ERR(res
) ? " [error]" : "");
265 * Clone an NFS4 server record on xdev traversal (FSID-change)
267 static struct dentry
*
268 nfs4_xdev_mount(struct file_system_type
*fs_type
, int flags
,
269 const char *dev_name
, void *raw_data
)
271 struct nfs_mount_info mount_info
= {
272 .fill_super
= nfs_clone_super
,
273 .set_security
= nfs_clone_sb_security
,
276 return nfs_xdev_mount_common(&nfs4_fs_type
, flags
, dev_name
, &mount_info
);
279 static struct dentry
*
280 nfs4_remote_referral_mount(struct file_system_type
*fs_type
, int flags
,
281 const char *dev_name
, void *raw_data
)
283 struct nfs_mount_info mount_info
= {
284 .fill_super
= nfs4_fill_super
,
285 .set_security
= nfs_clone_sb_security
,
288 struct nfs_server
*server
;
289 struct dentry
*mntroot
= ERR_PTR(-ENOMEM
);
291 dprintk("--> nfs4_referral_get_sb()\n");
293 mount_info
.mntfh
= nfs_alloc_fhandle();
294 if (mount_info
.cloned
== NULL
|| mount_info
.mntfh
== NULL
)
297 /* create a new volume representation */
298 server
= nfs4_create_referral_server(mount_info
.cloned
, mount_info
.mntfh
);
299 if (IS_ERR(server
)) {
300 mntroot
= ERR_CAST(server
);
304 mntroot
= nfs_fs_mount_common(server
, flags
, dev_name
, &mount_info
, &nfs_v4
);
306 nfs_free_fhandle(mount_info
.mntfh
);
311 * Create an NFS4 server record on referral traversal
313 static struct dentry
*nfs4_referral_mount(struct file_system_type
*fs_type
,
314 int flags
, const char *dev_name
, void *raw_data
)
316 struct nfs_clone_mount
*data
= raw_data
;
318 struct vfsmount
*root_mnt
;
321 dprintk("--> nfs4_referral_mount()\n");
323 export_path
= data
->mnt_path
;
324 data
->mnt_path
= "/";
326 root_mnt
= nfs_do_root_mount(&nfs4_remote_referral_fs_type
,
327 flags
, data
, data
->hostname
);
328 data
->mnt_path
= export_path
;
330 res
= nfs_follow_remote_path(root_mnt
, export_path
);
331 dprintk("<-- nfs4_referral_mount() = %ld%s\n",
332 IS_ERR(res
) ? PTR_ERR(res
) : 0,
333 IS_ERR(res
) ? " [error]" : "");
338 int __init
init_nfs_v4(void)
342 err
= nfs_idmap_init();
346 err
= nfs4_register_sysctl();
350 err
= register_filesystem(&nfs4_fs_type
);
354 register_nfs_version(&nfs_v4
);
357 nfs4_unregister_sysctl();
364 void exit_nfs_v4(void)
366 unregister_nfs_version(&nfs_v4
);
367 unregister_filesystem(&nfs4_fs_type
);
368 nfs4_unregister_sysctl();