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>
9 #include "delegation.h"
15 #define NFSDBG_FACILITY NFSDBG_VFS
17 static int nfs4_write_inode(struct inode
*inode
, struct writeback_control
*wbc
);
18 static void nfs4_evict_inode(struct inode
*inode
);
19 static struct dentry
*nfs4_remote_mount(struct file_system_type
*fs_type
,
20 int flags
, const char *dev_name
, void *raw_data
);
21 static struct dentry
*nfs4_referral_mount(struct file_system_type
*fs_type
,
22 int flags
, const char *dev_name
, void *raw_data
);
23 static struct dentry
*nfs4_remote_referral_mount(struct file_system_type
*fs_type
,
24 int flags
, const char *dev_name
, void *raw_data
);
26 static struct file_system_type nfs4_fs_type
= {
29 .mount
= nfs_fs_mount
,
30 .kill_sb
= nfs_kill_super
,
31 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
34 static struct file_system_type nfs4_remote_fs_type
= {
37 .mount
= nfs4_remote_mount
,
38 .kill_sb
= nfs_kill_super
,
39 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
42 static struct file_system_type nfs4_remote_referral_fs_type
= {
45 .mount
= nfs4_remote_referral_mount
,
46 .kill_sb
= nfs_kill_super
,
47 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
50 struct file_system_type nfs4_referral_fs_type
= {
53 .mount
= nfs4_referral_mount
,
54 .kill_sb
= nfs_kill_super
,
55 .fs_flags
= FS_RENAME_DOES_D_MOVE
|FS_REVAL_DOT
|FS_BINARY_MOUNTDATA
,
58 static const struct super_operations nfs4_sops
= {
59 .alloc_inode
= nfs_alloc_inode
,
60 .destroy_inode
= nfs_destroy_inode
,
61 .write_inode
= nfs4_write_inode
,
62 .put_super
= nfs_put_super
,
64 .evict_inode
= nfs4_evict_inode
,
65 .umount_begin
= nfs_umount_begin
,
66 .show_options
= nfs_show_options
,
67 .show_devname
= nfs_show_devname
,
68 .show_path
= nfs_show_path
,
69 .show_stats
= nfs_show_stats
,
70 .remount_fs
= nfs_remount
,
73 struct nfs_subversion nfs_v4
= {
75 .nfs_fs
= &nfs4_fs_type
,
76 .rpc_vers
= &nfs_version4
,
77 .rpc_ops
= &nfs_v4_clientops
,
79 .xattr
= nfs4_xattr_handlers
,
82 static int nfs4_write_inode(struct inode
*inode
, struct writeback_control
*wbc
)
84 int ret
= nfs_write_inode(inode
, wbc
);
86 if (ret
>= 0 && test_bit(NFS_INO_LAYOUTCOMMIT
, &NFS_I(inode
)->flags
)) {
90 if (wbc
->sync_mode
== WB_SYNC_NONE
)
93 status
= pnfs_layoutcommit_inode(inode
, sync
);
101 * Clean out any remaining NFSv4 state that might be left over due
102 * to open() calls that passed nfs_atomic_lookup, but failed to call
105 static void nfs4_evict_inode(struct inode
*inode
)
107 truncate_inode_pages(&inode
->i_data
, 0);
109 pnfs_return_layout(inode
);
110 pnfs_destroy_layout(NFS_I(inode
));
111 /* If we are holding a delegation, return it! */
112 nfs_inode_return_delegation_noreclaim(inode
);
113 /* First call standard NFS clear_inode() code */
114 nfs_clear_inode(inode
);
118 * Get the superblock for the NFS4 root partition
120 static struct dentry
*
121 nfs4_remote_mount(struct file_system_type
*fs_type
, int flags
,
122 const char *dev_name
, void *info
)
124 struct nfs_mount_info
*mount_info
= info
;
125 struct nfs_server
*server
;
126 struct dentry
*mntroot
= ERR_PTR(-ENOMEM
);
128 mount_info
->set_security
= nfs_set_sb_security
;
130 /* Get a volume representation */
131 server
= nfs4_create_server(mount_info
, &nfs_v4
);
132 if (IS_ERR(server
)) {
133 mntroot
= ERR_CAST(server
);
137 mntroot
= nfs_fs_mount_common(server
, flags
, dev_name
, mount_info
, &nfs_v4
);
143 static struct vfsmount
*nfs_do_root_mount(struct file_system_type
*fs_type
,
144 int flags
, void *data
, const char *hostname
)
146 struct vfsmount
*root_mnt
;
150 len
= strlen(hostname
) + 5;
151 root_devname
= kmalloc(len
, GFP_KERNEL
);
152 if (root_devname
== NULL
)
153 return ERR_PTR(-ENOMEM
);
154 /* Does hostname needs to be enclosed in brackets? */
155 if (strchr(hostname
, ':'))
156 snprintf(root_devname
, len
, "[%s]:/", hostname
);
158 snprintf(root_devname
, len
, "%s:/", hostname
);
159 root_mnt
= vfs_kern_mount(fs_type
, flags
, root_devname
, data
);
164 struct nfs_referral_count
{
165 struct list_head list
;
166 const struct task_struct
*task
;
167 unsigned int referral_count
;
170 static LIST_HEAD(nfs_referral_count_list
);
171 static DEFINE_SPINLOCK(nfs_referral_count_list_lock
);
173 static struct nfs_referral_count
*nfs_find_referral_count(void)
175 struct nfs_referral_count
*p
;
177 list_for_each_entry(p
, &nfs_referral_count_list
, list
) {
178 if (p
->task
== current
)
184 #define NFS_MAX_NESTED_REFERRALS 2
186 static int nfs_referral_loop_protect(void)
188 struct nfs_referral_count
*p
, *new;
191 new = kmalloc(sizeof(*new), GFP_KERNEL
);
195 new->referral_count
= 1;
198 spin_lock(&nfs_referral_count_list_lock
);
199 p
= nfs_find_referral_count();
201 if (p
->referral_count
>= NFS_MAX_NESTED_REFERRALS
)
206 list_add(&new->list
, &nfs_referral_count_list
);
209 spin_unlock(&nfs_referral_count_list_lock
);
215 static void nfs_referral_loop_unprotect(void)
217 struct nfs_referral_count
*p
;
219 spin_lock(&nfs_referral_count_list_lock
);
220 p
= nfs_find_referral_count();
222 if (p
->referral_count
== 0)
226 spin_unlock(&nfs_referral_count_list_lock
);
230 static struct dentry
*nfs_follow_remote_path(struct vfsmount
*root_mnt
,
231 const char *export_path
)
233 struct dentry
*dentry
;
236 if (IS_ERR(root_mnt
))
237 return ERR_CAST(root_mnt
);
239 err
= nfs_referral_loop_protect();
245 dentry
= mount_subtree(root_mnt
, export_path
);
246 nfs_referral_loop_unprotect();
251 struct dentry
*nfs4_try_mount(int flags
, const char *dev_name
,
252 struct nfs_mount_info
*mount_info
,
253 struct nfs_subversion
*nfs_mod
)
256 struct vfsmount
*root_mnt
;
258 struct nfs_parsed_mount_data
*data
= mount_info
->parsed
;
260 dfprintk(MOUNT
, "--> nfs4_try_mount()\n");
262 export_path
= data
->nfs_server
.export_path
;
263 data
->nfs_server
.export_path
= "/";
264 root_mnt
= nfs_do_root_mount(&nfs4_remote_fs_type
, flags
, mount_info
,
265 data
->nfs_server
.hostname
);
266 data
->nfs_server
.export_path
= export_path
;
268 res
= nfs_follow_remote_path(root_mnt
, export_path
);
270 dfprintk(MOUNT
, "<-- nfs4_try_mount() = %ld%s\n",
271 IS_ERR(res
) ? PTR_ERR(res
) : 0,
272 IS_ERR(res
) ? " [error]" : "");
276 static struct dentry
*
277 nfs4_remote_referral_mount(struct file_system_type
*fs_type
, int flags
,
278 const char *dev_name
, void *raw_data
)
280 struct nfs_mount_info mount_info
= {
281 .fill_super
= nfs_fill_super
,
282 .set_security
= nfs_clone_sb_security
,
285 struct nfs_server
*server
;
286 struct dentry
*mntroot
= ERR_PTR(-ENOMEM
);
288 dprintk("--> nfs4_referral_get_sb()\n");
290 mount_info
.mntfh
= nfs_alloc_fhandle();
291 if (mount_info
.cloned
== NULL
|| mount_info
.mntfh
== NULL
)
294 /* create a new volume representation */
295 server
= nfs4_create_referral_server(mount_info
.cloned
, mount_info
.mntfh
);
296 if (IS_ERR(server
)) {
297 mntroot
= ERR_CAST(server
);
301 mntroot
= nfs_fs_mount_common(server
, flags
, dev_name
, &mount_info
, &nfs_v4
);
303 nfs_free_fhandle(mount_info
.mntfh
);
308 * Create an NFS4 server record on referral traversal
310 static struct dentry
*nfs4_referral_mount(struct file_system_type
*fs_type
,
311 int flags
, const char *dev_name
, void *raw_data
)
313 struct nfs_clone_mount
*data
= raw_data
;
315 struct vfsmount
*root_mnt
;
318 dprintk("--> nfs4_referral_mount()\n");
320 export_path
= data
->mnt_path
;
321 data
->mnt_path
= "/";
323 root_mnt
= nfs_do_root_mount(&nfs4_remote_referral_fs_type
,
324 flags
, data
, data
->hostname
);
325 data
->mnt_path
= export_path
;
327 res
= nfs_follow_remote_path(root_mnt
, export_path
);
328 dprintk("<-- nfs4_referral_mount() = %ld%s\n",
329 IS_ERR(res
) ? PTR_ERR(res
) : 0,
330 IS_ERR(res
) ? " [error]" : "");
335 static int __init
init_nfs_v4(void)
339 err
= nfs_idmap_init();
343 err
= nfs4_register_sysctl();
347 err
= register_filesystem(&nfs4_fs_type
);
351 register_nfs_version(&nfs_v4
);
354 nfs4_unregister_sysctl();
361 static void __exit
exit_nfs_v4(void)
363 unregister_nfs_version(&nfs_v4
);
364 unregister_filesystem(&nfs4_fs_type
);
365 nfs4_unregister_sysctl();
369 MODULE_LICENSE("GPL");
371 module_init(init_nfs_v4
);
372 module_exit(exit_nfs_v4
);