]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/nfs/super.c
RPC: Clean up rpc_execute...
[mirror_ubuntu-artful-kernel.git] / fs / nfs / super.c
CommitLineData
f7b422b1
DH
1/*
2 * linux/fs/nfs/super.c
3 *
4 * Copyright (C) 1992 Rick Sladkey
5 *
6 * nfs superblock handling functions
7 *
8 * Modularised by Alan Cox <Alan.Cox@linux.org>, while hacking some
9 * experimental NFS changes. Modularisation taken straight from SYS5 fs.
10 *
11 * Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
12 * J.S.Peatfield@damtp.cam.ac.uk
13 *
14 * Split from inode.c by David Howells <dhowells@redhat.com>
15 *
54ceac45
DH
16 * - superblocks are indexed on server only - all inodes, dentries, etc. associated with a
17 * particular server are held in the same superblock
18 * - NFS superblocks can have several effective roots to the dentry tree
19 * - directory type roots are spliced into the tree when a path from one root reaches the root
20 * of another (see nfs_lookup())
f7b422b1
DH
21 */
22
f7b422b1
DH
23#include <linux/module.h>
24#include <linux/init.h>
25
26#include <linux/time.h>
27#include <linux/kernel.h>
28#include <linux/mm.h>
29#include <linux/string.h>
30#include <linux/stat.h>
31#include <linux/errno.h>
32#include <linux/unistd.h>
33#include <linux/sunrpc/clnt.h>
34#include <linux/sunrpc/stats.h>
35#include <linux/sunrpc/metrics.h>
36#include <linux/nfs_fs.h>
37#include <linux/nfs_mount.h>
38#include <linux/nfs4_mount.h>
39#include <linux/lockd/bind.h>
40#include <linux/smp_lock.h>
41#include <linux/seq_file.h>
42#include <linux/mount.h>
43#include <linux/nfs_idmap.h>
44#include <linux/vfs.h>
45#include <linux/inet.h>
46#include <linux/nfs_xdr.h>
47
48#include <asm/system.h>
49#include <asm/uaccess.h>
50
51#include "nfs4_fs.h"
52#include "callback.h"
53#include "delegation.h"
54#include "iostat.h"
55#include "internal.h"
56
57#define NFSDBG_FACILITY NFSDBG_VFS
58
f7b422b1 59static void nfs_umount_begin(struct vfsmount *, int);
816724e6 60static int nfs_statfs(struct dentry *, struct kstatfs *);
f7b422b1
DH
61static int nfs_show_options(struct seq_file *, struct vfsmount *);
62static int nfs_show_stats(struct seq_file *, struct vfsmount *);
816724e6 63static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
54ceac45 64static int nfs_xdev_get_sb(struct file_system_type *fs_type,
816724e6 65 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
f7b422b1
DH
66static void nfs_kill_super(struct super_block *);
67
68static struct file_system_type nfs_fs_type = {
69 .owner = THIS_MODULE,
70 .name = "nfs",
71 .get_sb = nfs_get_sb,
72 .kill_sb = nfs_kill_super,
349457cc 73 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b1
DH
74};
75
54ceac45 76struct file_system_type nfs_xdev_fs_type = {
f7b422b1
DH
77 .owner = THIS_MODULE,
78 .name = "nfs",
54ceac45 79 .get_sb = nfs_xdev_get_sb,
f7b422b1 80 .kill_sb = nfs_kill_super,
349457cc 81 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b1
DH
82};
83
84static struct super_operations nfs_sops = {
85 .alloc_inode = nfs_alloc_inode,
86 .destroy_inode = nfs_destroy_inode,
87 .write_inode = nfs_write_inode,
88 .statfs = nfs_statfs,
89 .clear_inode = nfs_clear_inode,
90 .umount_begin = nfs_umount_begin,
91 .show_options = nfs_show_options,
92 .show_stats = nfs_show_stats,
93};
94
95#ifdef CONFIG_NFS_V4
816724e6
TM
96static int nfs4_get_sb(struct file_system_type *fs_type,
97 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
54ceac45
DH
98static int nfs4_xdev_get_sb(struct file_system_type *fs_type,
99 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
100static int nfs4_referral_get_sb(struct file_system_type *fs_type,
101 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
f7b422b1
DH
102static void nfs4_kill_super(struct super_block *sb);
103
104static struct file_system_type nfs4_fs_type = {
105 .owner = THIS_MODULE,
106 .name = "nfs4",
107 .get_sb = nfs4_get_sb,
108 .kill_sb = nfs4_kill_super,
349457cc 109 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b1
DH
110};
111
54ceac45 112struct file_system_type nfs4_xdev_fs_type = {
f7b422b1
DH
113 .owner = THIS_MODULE,
114 .name = "nfs4",
54ceac45 115 .get_sb = nfs4_xdev_get_sb,
f7b422b1 116 .kill_sb = nfs4_kill_super,
349457cc 117 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b1
DH
118};
119
54ceac45 120struct file_system_type nfs4_referral_fs_type = {
f7b422b1
DH
121 .owner = THIS_MODULE,
122 .name = "nfs4",
54ceac45 123 .get_sb = nfs4_referral_get_sb,
f7b422b1 124 .kill_sb = nfs4_kill_super,
349457cc 125 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b1
DH
126};
127
128static struct super_operations nfs4_sops = {
129 .alloc_inode = nfs_alloc_inode,
130 .destroy_inode = nfs_destroy_inode,
131 .write_inode = nfs_write_inode,
132 .statfs = nfs_statfs,
133 .clear_inode = nfs4_clear_inode,
134 .umount_begin = nfs_umount_begin,
135 .show_options = nfs_show_options,
136 .show_stats = nfs_show_stats,
137};
138#endif
139
979df72e
TM
140static struct shrinker *acl_shrinker;
141
f7b422b1
DH
142/*
143 * Register the NFS filesystems
144 */
145int __init register_nfs_fs(void)
146{
147 int ret;
148
149 ret = register_filesystem(&nfs_fs_type);
150 if (ret < 0)
151 goto error_0;
152
153#ifdef CONFIG_NFS_V4
154 ret = nfs_register_sysctl();
155 if (ret < 0)
156 goto error_1;
157 ret = register_filesystem(&nfs4_fs_type);
158 if (ret < 0)
159 goto error_2;
160#endif
979df72e 161 acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker);
f7b422b1
DH
162 return 0;
163
164#ifdef CONFIG_NFS_V4
165error_2:
166 nfs_unregister_sysctl();
167error_1:
168 unregister_filesystem(&nfs_fs_type);
169#endif
170error_0:
171 return ret;
172}
173
174/*
175 * Unregister the NFS filesystems
176 */
177void __exit unregister_nfs_fs(void)
178{
979df72e
TM
179 if (acl_shrinker != NULL)
180 remove_shrinker(acl_shrinker);
f7b422b1
DH
181#ifdef CONFIG_NFS_V4
182 unregister_filesystem(&nfs4_fs_type);
183 nfs_unregister_sysctl();
184#endif
185 unregister_filesystem(&nfs_fs_type);
186}
187
188/*
189 * Deliver file system statistics to userspace
190 */
816724e6 191static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
f7b422b1 192{
0c7d90cf 193 struct nfs_server *server = NFS_SB(dentry->d_sb);
f7b422b1
DH
194 unsigned char blockbits;
195 unsigned long blockres;
0c7d90cf 196 struct nfs_fh *fh = NFS_FH(dentry->d_inode);
f7b422b1
DH
197 struct nfs_fattr fattr;
198 struct nfs_fsstat res = {
199 .fattr = &fattr,
200 };
201 int error;
202
203 lock_kernel();
204
8fa5c000 205 error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
f7b422b1
DH
206 buf->f_type = NFS_SUPER_MAGIC;
207 if (error < 0)
208 goto out_err;
209
210 /*
211 * Current versions of glibc do not correctly handle the
212 * case where f_frsize != f_bsize. Eventually we want to
213 * report the value of wtmult in this field.
214 */
0c7d90cf 215 buf->f_frsize = dentry->d_sb->s_blocksize;
f7b422b1
DH
216
217 /*
218 * On most *nix systems, f_blocks, f_bfree, and f_bavail
219 * are reported in units of f_frsize. Linux hasn't had
220 * an f_frsize field in its statfs struct until recently,
221 * thus historically Linux's sys_statfs reports these
222 * fields in units of f_bsize.
223 */
0c7d90cf
DH
224 buf->f_bsize = dentry->d_sb->s_blocksize;
225 blockbits = dentry->d_sb->s_blocksize_bits;
f7b422b1
DH
226 blockres = (1 << blockbits) - 1;
227 buf->f_blocks = (res.tbytes + blockres) >> blockbits;
228 buf->f_bfree = (res.fbytes + blockres) >> blockbits;
229 buf->f_bavail = (res.abytes + blockres) >> blockbits;
230
231 buf->f_files = res.tfiles;
232 buf->f_ffree = res.afiles;
233
234 buf->f_namelen = server->namelen;
235 out:
236 unlock_kernel();
237 return 0;
238
239 out_err:
240 dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
241 buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
242 goto out;
243
244}
245
7d4e2747
DH
246/*
247 * Map the security flavour number to a name
248 */
81039f1f
TM
249static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
250{
7d4e2747 251 static const struct {
81039f1f
TM
252 rpc_authflavor_t flavour;
253 const char *str;
254 } sec_flavours[] = {
255 { RPC_AUTH_NULL, "null" },
256 { RPC_AUTH_UNIX, "sys" },
257 { RPC_AUTH_GSS_KRB5, "krb5" },
258 { RPC_AUTH_GSS_KRB5I, "krb5i" },
259 { RPC_AUTH_GSS_KRB5P, "krb5p" },
260 { RPC_AUTH_GSS_LKEY, "lkey" },
261 { RPC_AUTH_GSS_LKEYI, "lkeyi" },
262 { RPC_AUTH_GSS_LKEYP, "lkeyp" },
263 { RPC_AUTH_GSS_SPKM, "spkm" },
264 { RPC_AUTH_GSS_SPKMI, "spkmi" },
265 { RPC_AUTH_GSS_SPKMP, "spkmp" },
266 { -1, "unknown" }
267 };
268 int i;
269
270 for (i=0; sec_flavours[i].flavour != -1; i++) {
271 if (sec_flavours[i].flavour == flavour)
272 break;
273 }
274 return sec_flavours[i].str;
275}
276
f7b422b1
DH
277/*
278 * Describe the mount options in force on this server representation
279 */
280static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
281{
509de811 282 static const struct proc_nfs_info {
f7b422b1 283 int flag;
509de811
DH
284 const char *str;
285 const char *nostr;
f7b422b1
DH
286 } nfs_info[] = {
287 { NFS_MOUNT_SOFT, ",soft", ",hard" },
288 { NFS_MOUNT_INTR, ",intr", "" },
289 { NFS_MOUNT_NOCTO, ",nocto", "" },
290 { NFS_MOUNT_NOAC, ",noac", "" },
291 { NFS_MOUNT_NONLM, ",nolock", "" },
292 { NFS_MOUNT_NOACL, ",noacl", "" },
293 { 0, NULL, NULL }
294 };
509de811 295 const struct proc_nfs_info *nfs_infop;
8fa5c000 296 struct nfs_client *clp = nfss->nfs_client;
f7b422b1 297 char buf[12];
509de811 298 const char *proto;
f7b422b1 299
8fa5c000 300 seq_printf(m, ",vers=%d", clp->rpc_ops->version);
f7b422b1
DH
301 seq_printf(m, ",rsize=%d", nfss->rsize);
302 seq_printf(m, ",wsize=%d", nfss->wsize);
303 if (nfss->acregmin != 3*HZ || showdefaults)
304 seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
305 if (nfss->acregmax != 60*HZ || showdefaults)
306 seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
307 if (nfss->acdirmin != 30*HZ || showdefaults)
308 seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
309 if (nfss->acdirmax != 60*HZ || showdefaults)
310 seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
311 for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
312 if (nfss->flags & nfs_infop->flag)
313 seq_puts(m, nfs_infop->str);
314 else
315 seq_puts(m, nfs_infop->nostr);
316 }
317 switch (nfss->client->cl_xprt->prot) {
318 case IPPROTO_TCP:
319 proto = "tcp";
320 break;
321 case IPPROTO_UDP:
322 proto = "udp";
323 break;
324 default:
325 snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot);
326 proto = buf;
327 }
328 seq_printf(m, ",proto=%s", proto);
5006a76c
DH
329 seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ);
330 seq_printf(m, ",retrans=%u", clp->retrans_count);
81039f1f 331 seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
f7b422b1
DH
332}
333
334/*
335 * Describe the mount options on this VFS mountpoint
336 */
337static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
338{
339 struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
340
341 nfs_show_mount_options(m, nfss, 0);
342
343 seq_puts(m, ",addr=");
54ceac45 344 seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\");
f7b422b1
DH
345
346 return 0;
347}
348
349/*
350 * Present statistical information for this VFS mountpoint
351 */
352static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
353{
354 int i, cpu;
355 struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
356 struct rpc_auth *auth = nfss->client->cl_auth;
357 struct nfs_iostats totals = { };
358
359 seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
360
361 /*
362 * Display all mount option settings
363 */
364 seq_printf(m, "\n\topts:\t");
365 seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
366 seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
367 seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : "");
368 seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
369 nfs_show_mount_options(m, nfss, 1);
370
371 seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
372
373 seq_printf(m, "\n\tcaps:\t");
374 seq_printf(m, "caps=0x%x", nfss->caps);
375 seq_printf(m, ",wtmult=%d", nfss->wtmult);
376 seq_printf(m, ",dtsize=%d", nfss->dtsize);
377 seq_printf(m, ",bsize=%d", nfss->bsize);
378 seq_printf(m, ",namelen=%d", nfss->namelen);
379
380#ifdef CONFIG_NFS_V4
8fa5c000 381 if (nfss->nfs_client->cl_nfsversion == 4) {
f7b422b1
DH
382 seq_printf(m, "\n\tnfsv4:\t");
383 seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
384 seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
385 seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
386 }
387#endif
388
389 /*
390 * Display security flavor in effect for this mount
391 */
392 seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
393 if (auth->au_flavor)
394 seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
395
396 /*
397 * Display superblock I/O counters
398 */
399 for_each_possible_cpu(cpu) {
400 struct nfs_iostats *stats;
401
402 preempt_disable();
403 stats = per_cpu_ptr(nfss->io_stats, cpu);
404
405 for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
406 totals.events[i] += stats->events[i];
407 for (i = 0; i < __NFSIOS_BYTESMAX; i++)
408 totals.bytes[i] += stats->bytes[i];
409
410 preempt_enable();
411 }
412
413 seq_printf(m, "\n\tevents:\t");
414 for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
415 seq_printf(m, "%lu ", totals.events[i]);
416 seq_printf(m, "\n\tbytes:\t");
417 for (i = 0; i < __NFSIOS_BYTESMAX; i++)
418 seq_printf(m, "%Lu ", totals.bytes[i]);
419 seq_printf(m, "\n");
420
421 rpc_print_iostats(m, nfss->client);
422
423 return 0;
424}
425
426/*
427 * Begin unmount by attempting to remove all automounted mountpoints we added
54ceac45 428 * in response to xdev traversals and referrals
f7b422b1
DH
429 */
430static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
431{
f7b422b1 432 shrink_submounts(vfsmnt, &nfs_automount_list);
f7b422b1
DH
433}
434
435/*
54ceac45
DH
436 * Validate the NFS2/NFS3 mount data
437 * - fills in the mount root filehandle
f7b422b1 438 */
54ceac45
DH
439static int nfs_validate_mount_data(struct nfs_mount_data *data,
440 struct nfs_fh *mntfh)
f7b422b1 441{
54ceac45
DH
442 if (data == NULL) {
443 dprintk("%s: missing data argument\n", __FUNCTION__);
444 return -EINVAL;
f7b422b1
DH
445 }
446
54ceac45
DH
447 if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
448 dprintk("%s: bad mount version\n", __FUNCTION__);
449 return -EINVAL;
450 }
f7b422b1 451
54ceac45
DH
452 switch (data->version) {
453 case 1:
454 data->namlen = 0;
455 case 2:
456 data->bsize = 0;
457 case 3:
458 if (data->flags & NFS_MOUNT_VER3) {
459 dprintk("%s: mount structure version %d does not support NFSv3\n",
460 __FUNCTION__,
461 data->version);
462 return -EINVAL;
463 }
464 data->root.size = NFS2_FHSIZE;
465 memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
466 case 4:
467 if (data->flags & NFS_MOUNT_SECFLAVOUR) {
468 dprintk("%s: mount structure version %d does not support strong security\n",
469 __FUNCTION__,
470 data->version);
471 return -EINVAL;
472 }
54ceac45
DH
473 case 5:
474 memset(data->context, 0, sizeof(data->context));
f7b422b1 475 }
54ceac45 476
36b15c54
TM
477 /* Set the pseudoflavor */
478 if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
479 data->pseudoflavor = RPC_AUTH_UNIX;
480
54ceac45
DH
481#ifndef CONFIG_NFS_V3
482 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
483 if (data->flags & NFS_MOUNT_VER3) {
484 dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
485 return -EPROTONOSUPPORT;
f7b422b1 486 }
54ceac45 487#endif /* CONFIG_NFS_V3 */
f7b422b1 488
54ceac45
DH
489 /* We now require that the mount process passes the remote address */
490 if (data->addr.sin_addr.s_addr == INADDR_ANY) {
491 dprintk("%s: mount program didn't pass remote address!\n",
492 __FUNCTION__);
493 return -EINVAL;
f7b422b1 494 }
f7b422b1 495
54ceac45
DH
496 /* Prepare the root filehandle */
497 if (data->flags & NFS_MOUNT_VER3)
498 mntfh->size = data->root.size;
499 else
500 mntfh->size = NFS2_FHSIZE;
f7b422b1 501
54ceac45
DH
502 if (mntfh->size > sizeof(mntfh->data)) {
503 dprintk("%s: invalid root filehandle\n", __FUNCTION__);
504 return -EINVAL;
505 }
506
507 memcpy(mntfh->data, data->root.data, mntfh->size);
508 if (mntfh->size < sizeof(mntfh->data))
509 memset(mntfh->data + mntfh->size, 0,
510 sizeof(mntfh->data) - mntfh->size);
f7b422b1 511
f7b422b1 512 return 0;
f7b422b1
DH
513}
514
f7b422b1 515/*
54ceac45 516 * Initialise the common bits of the superblock
f7b422b1 517 */
54ceac45 518static inline void nfs_initialise_sb(struct super_block *sb)
f7b422b1 519{
54ceac45 520 struct nfs_server *server = NFS_SB(sb);
5006a76c 521
54ceac45 522 sb->s_magic = NFS_SUPER_MAGIC;
f7b422b1 523
54ceac45
DH
524 /* We probably want something more informative here */
525 snprintf(sb->s_id, sizeof(sb->s_id),
526 "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
5006a76c 527
54ceac45
DH
528 if (sb->s_blocksize == 0)
529 sb->s_blocksize = nfs_block_bits(server->wsize,
530 &sb->s_blocksize_bits);
f7b422b1 531
54ceac45
DH
532 if (server->flags & NFS_MOUNT_NOAC)
533 sb->s_flags |= MS_SYNCHRONOUS;
f7b422b1 534
54ceac45 535 nfs_super_set_maxbytes(sb, server->maxfilesize);
f7b422b1
DH
536}
537
538/*
54ceac45 539 * Finish setting up an NFS2/3 superblock
f7b422b1 540 */
54ceac45 541static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data)
f7b422b1
DH
542{
543 struct nfs_server *server = NFS_SB(sb);
5006a76c 544
54ceac45
DH
545 sb->s_blocksize_bits = 0;
546 sb->s_blocksize = 0;
547 if (data->bsize)
548 sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
f7b422b1 549
54ceac45
DH
550 if (server->flags & NFS_MOUNT_VER3) {
551 /* The VFS shouldn't apply the umask to mode bits. We will do
552 * so ourselves when necessary.
553 */
554 sb->s_flags |= MS_POSIXACL;
555 sb->s_time_gran = 1;
816724e6 556 }
54ceac45
DH
557
558 sb->s_op = &nfs_sops;
559 nfs_initialise_sb(sb);
f7b422b1
DH
560}
561
562/*
54ceac45 563 * Finish setting up a cloned NFS2/3 superblock
f7b422b1 564 */
54ceac45
DH
565static void nfs_clone_super(struct super_block *sb,
566 const struct super_block *old_sb)
f7b422b1 567{
54ceac45
DH
568 struct nfs_server *server = NFS_SB(sb);
569
570 sb->s_blocksize_bits = old_sb->s_blocksize_bits;
571 sb->s_blocksize = old_sb->s_blocksize;
572 sb->s_maxbytes = old_sb->s_maxbytes;
f7b422b1 573
f7b422b1 574 if (server->flags & NFS_MOUNT_VER3) {
54ceac45
DH
575 /* The VFS shouldn't apply the umask to mode bits. We will do
576 * so ourselves when necessary.
f7b422b1
DH
577 */
578 sb->s_flags |= MS_POSIXACL;
f7b422b1 579 sb->s_time_gran = 1;
f7b422b1
DH
580 }
581
54ceac45
DH
582 sb->s_op = old_sb->s_op;
583 nfs_initialise_sb(sb);
f7b422b1
DH
584}
585
54ceac45 586static int nfs_set_super(struct super_block *s, void *_server)
f7b422b1 587{
54ceac45
DH
588 struct nfs_server *server = _server;
589 int ret;
590
591 s->s_fs_info = server;
592 ret = set_anon_super(s, server);
593 if (ret == 0)
594 server->s_dev = s->s_dev;
595 return ret;
f7b422b1
DH
596}
597
598static int nfs_compare_super(struct super_block *sb, void *data)
599{
54ceac45 600 struct nfs_server *server = data, *old = NFS_SB(sb);
f7b422b1 601
54ceac45 602 if (old->nfs_client != server->nfs_client)
f7b422b1 603 return 0;
54ceac45 604 if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
f7b422b1 605 return 0;
54ceac45 606 return 1;
f7b422b1
DH
607}
608
816724e6
TM
609static int nfs_get_sb(struct file_system_type *fs_type,
610 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
f7b422b1 611{
f7b422b1
DH
612 struct nfs_server *server = NULL;
613 struct super_block *s;
54ceac45 614 struct nfs_fh mntfh;
f7b422b1 615 struct nfs_mount_data *data = raw_data;
54ceac45
DH
616 struct dentry *mntroot;
617 int error;
f7b422b1 618
54ceac45
DH
619 /* Validate the mount data */
620 error = nfs_validate_mount_data(data, &mntfh);
621 if (error < 0)
622 return error;
f7b422b1 623
54ceac45
DH
624 /* Get a volume representation */
625 server = nfs_create_server(data, &mntfh);
626 if (IS_ERR(server)) {
627 error = PTR_ERR(server);
816724e6 628 goto out_err_noserver;
f7b422b1
DH
629 }
630
54ceac45 631 /* Get a superblock - note that we may end up sharing one that already exists */
f7b422b1 632 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
816724e6
TM
633 if (IS_ERR(s)) {
634 error = PTR_ERR(s);
54ceac45 635 goto out_err_nosb;
816724e6
TM
636 }
637
54ceac45
DH
638 if (s->s_fs_info != server) {
639 nfs_free_server(server);
640 server = NULL;
641 }
f7b422b1 642
54ceac45
DH
643 if (!s->s_root) {
644 /* initial superblock/root creation */
645 s->s_flags = flags;
646 nfs_fill_super(s, data);
647 }
f7b422b1 648
54ceac45
DH
649 mntroot = nfs_get_root(s, &mntfh);
650 if (IS_ERR(mntroot)) {
651 error = PTR_ERR(mntroot);
652 goto error_splat_super;
f7b422b1 653 }
816724e6 654
54ceac45
DH
655 s->s_flags |= MS_ACTIVE;
656 mnt->mnt_sb = s;
657 mnt->mnt_root = mntroot;
658 return 0;
816724e6 659
54ceac45
DH
660out_err_nosb:
661 nfs_free_server(server);
816724e6
TM
662out_err_noserver:
663 return error;
54ceac45
DH
664
665error_splat_super:
666 up_write(&s->s_umount);
667 deactivate_super(s);
668 return error;
f7b422b1
DH
669}
670
54ceac45
DH
671/*
672 * Destroy an NFS2/3 superblock
673 */
f7b422b1
DH
674static void nfs_kill_super(struct super_block *s)
675{
676 struct nfs_server *server = NFS_SB(s);
677
678 kill_anon_super(s);
54ceac45 679 nfs_free_server(server);
f7b422b1
DH
680}
681
54ceac45
DH
682/*
683 * Clone an NFS2/3 server record on xdev traversal (FSID-change)
684 */
685static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
686 const char *dev_name, void *raw_data,
687 struct vfsmount *mnt)
f7b422b1
DH
688{
689 struct nfs_clone_mount *data = raw_data;
54ceac45
DH
690 struct super_block *s;
691 struct nfs_server *server;
692 struct dentry *mntroot;
693 int error;
f7b422b1 694
54ceac45 695 dprintk("--> nfs_xdev_get_sb()\n");
f7b422b1 696
54ceac45
DH
697 /* create a new volume representation */
698 server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
699 if (IS_ERR(server)) {
700 error = PTR_ERR(server);
701 goto out_err_noserver;
702 }
8fa5c000 703
54ceac45
DH
704 /* Get a superblock - note that we may end up sharing one that already exists */
705 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
706 if (IS_ERR(s)) {
707 error = PTR_ERR(s);
708 goto out_err_nosb;
709 }
5006a76c 710
54ceac45
DH
711 if (s->s_fs_info != server) {
712 nfs_free_server(server);
713 server = NULL;
f7b422b1 714 }
24c8dbbb 715
54ceac45
DH
716 if (!s->s_root) {
717 /* initial superblock/root creation */
718 s->s_flags = flags;
719 nfs_clone_super(s, data->sb);
720 }
f7b422b1 721
54ceac45
DH
722 mntroot = nfs_get_root(s, data->fh);
723 if (IS_ERR(mntroot)) {
724 error = PTR_ERR(mntroot);
725 goto error_splat_super;
f7b422b1
DH
726 }
727
54ceac45
DH
728 s->s_flags |= MS_ACTIVE;
729 mnt->mnt_sb = s;
730 mnt->mnt_root = mntroot;
f7b422b1 731
54ceac45
DH
732 dprintk("<-- nfs_xdev_get_sb() = 0\n");
733 return 0;
24c8dbbb 734
54ceac45
DH
735out_err_nosb:
736 nfs_free_server(server);
737out_err_noserver:
738 dprintk("<-- nfs_xdev_get_sb() = %d [error]\n", error);
739 return error;
f7b422b1 740
54ceac45
DH
741error_splat_super:
742 up_write(&s->s_umount);
743 deactivate_super(s);
744 dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error);
745 return error;
f7b422b1
DH
746}
747
54ceac45
DH
748#ifdef CONFIG_NFS_V4
749
f7b422b1 750/*
54ceac45 751 * Finish setting up a cloned NFS4 superblock
f7b422b1 752 */
54ceac45
DH
753static void nfs4_clone_super(struct super_block *sb,
754 const struct super_block *old_sb)
f7b422b1 755{
54ceac45
DH
756 sb->s_blocksize_bits = old_sb->s_blocksize_bits;
757 sb->s_blocksize = old_sb->s_blocksize;
758 sb->s_maxbytes = old_sb->s_maxbytes;
f7b422b1 759 sb->s_time_gran = 1;
54ceac45
DH
760 sb->s_op = old_sb->s_op;
761 nfs_initialise_sb(sb);
f7b422b1
DH
762}
763
54ceac45
DH
764/*
765 * Set up an NFS4 superblock
766 */
767static void nfs4_fill_super(struct super_block *sb)
f7b422b1 768{
54ceac45
DH
769 sb->s_time_gran = 1;
770 sb->s_op = &nfs4_sops;
771 nfs_initialise_sb(sb);
f7b422b1
DH
772}
773
54ceac45 774static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
f7b422b1
DH
775{
776 void *p = NULL;
777
778 if (!src->len)
779 return ERR_PTR(-EINVAL);
780 if (src->len < maxlen)
781 maxlen = src->len;
782 if (dst == NULL) {
783 p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
784 if (p == NULL)
785 return ERR_PTR(-ENOMEM);
786 }
787 if (copy_from_user(dst, src->data, maxlen)) {
788 kfree(p);
789 return ERR_PTR(-EFAULT);
790 }
791 dst[maxlen] = '\0';
792 return dst;
793}
794
54ceac45
DH
795/*
796 * Get the superblock for an NFS4 mountpoint
797 */
816724e6
TM
798static int nfs4_get_sb(struct file_system_type *fs_type,
799 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
f7b422b1 800{
f7b422b1 801 struct nfs4_mount_data *data = raw_data;
54ceac45
DH
802 struct super_block *s;
803 struct nfs_server *server;
804 struct sockaddr_in addr;
805 rpc_authflavor_t authflavour;
806 struct nfs_fh mntfh;
807 struct dentry *mntroot;
808 char *mntpath = NULL, *hostname = NULL, ip_addr[16];
f7b422b1 809 void *p;
54ceac45 810 int error;
f7b422b1
DH
811
812 if (data == NULL) {
813 dprintk("%s: missing data argument\n", __FUNCTION__);
816724e6 814 return -EINVAL;
f7b422b1
DH
815 }
816 if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
817 dprintk("%s: bad mount version\n", __FUNCTION__);
816724e6 818 return -EINVAL;
f7b422b1
DH
819 }
820
54ceac45
DH
821 /* We now require that the mount process passes the remote address */
822 if (data->host_addrlen != sizeof(addr))
823 return -EINVAL;
824
825 if (copy_from_user(&addr, data->host_addr, sizeof(addr)))
826 return -EFAULT;
827
828 if (addr.sin_family != AF_INET ||
829 addr.sin_addr.s_addr == INADDR_ANY
830 ) {
831 dprintk("%s: mount program didn't pass remote IP address!\n",
832 __FUNCTION__);
833 return -EINVAL;
834 }
51b6ded4
TM
835 /* RFC3530: The default port for NFS is 2049 */
836 if (addr.sin_port == 0)
575b5c78 837 addr.sin_port = htons(NFS_PORT);
54ceac45
DH
838
839 /* Grab the authentication type */
840 authflavour = RPC_AUTH_UNIX;
841 if (data->auth_flavourlen != 0) {
842 if (data->auth_flavourlen != 1) {
843 dprintk("%s: Invalid number of RPC auth flavours %d.\n",
844 __FUNCTION__, data->auth_flavourlen);
845 error = -EINVAL;
846 goto out_err_noserver;
847 }
848
849 if (copy_from_user(&authflavour, data->auth_flavours,
850 sizeof(authflavour))) {
851 error = -EFAULT;
852 goto out_err_noserver;
853 }
854 }
f7b422b1
DH
855
856 p = nfs_copy_user_string(NULL, &data->hostname, 256);
857 if (IS_ERR(p))
858 goto out_err;
54ceac45 859 hostname = p;
f7b422b1
DH
860
861 p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
862 if (IS_ERR(p))
863 goto out_err;
54ceac45 864 mntpath = p;
f7b422b1 865
54ceac45
DH
866 dprintk("MNTPATH: %s\n", mntpath);
867
868 p = nfs_copy_user_string(ip_addr, &data->client_addr,
869 sizeof(ip_addr) - 1);
f7b422b1
DH
870 if (IS_ERR(p))
871 goto out_err;
872
54ceac45
DH
873 /* Get a volume representation */
874 server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
875 authflavour, &mntfh);
876 if (IS_ERR(server)) {
877 error = PTR_ERR(server);
878 goto out_err_noserver;
f7b422b1
DH
879 }
880
54ceac45
DH
881 /* Get a superblock - note that we may end up sharing one that already exists */
882 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
816724e6
TM
883 if (IS_ERR(s)) {
884 error = PTR_ERR(s);
f7b422b1 885 goto out_free;
816724e6
TM
886 }
887
5dd3177a
TM
888 if (s->s_fs_info != server) {
889 nfs_free_server(server);
890 server = NULL;
891 }
892
54ceac45
DH
893 if (!s->s_root) {
894 /* initial superblock/root creation */
895 s->s_flags = flags;
54ceac45 896 nfs4_fill_super(s);
54ceac45 897 }
f7b422b1 898
54ceac45
DH
899 mntroot = nfs4_get_root(s, &mntfh);
900 if (IS_ERR(mntroot)) {
901 error = PTR_ERR(mntroot);
902 goto error_splat_super;
f7b422b1 903 }
54ceac45 904
f7b422b1 905 s->s_flags |= MS_ACTIVE;
54ceac45
DH
906 mnt->mnt_sb = s;
907 mnt->mnt_root = mntroot;
908 kfree(mntpath);
909 kfree(hostname);
910 return 0;
911
f7b422b1 912out_err:
816724e6 913 error = PTR_ERR(p);
54ceac45
DH
914 goto out_err_noserver;
915
f7b422b1 916out_free:
54ceac45
DH
917 nfs_free_server(server);
918out_err_noserver:
919 kfree(mntpath);
920 kfree(hostname);
816724e6 921 return error;
54ceac45
DH
922
923error_splat_super:
924 up_write(&s->s_umount);
925 deactivate_super(s);
926 goto out_err_noserver;
f7b422b1
DH
927}
928
929static void nfs4_kill_super(struct super_block *sb)
930{
931 struct nfs_server *server = NFS_SB(sb);
932
933 nfs_return_all_delegations(sb);
934 kill_anon_super(sb);
935
936 nfs4_renewd_prepare_shutdown(server);
54ceac45 937 nfs_free_server(server);
f7b422b1
DH
938}
939
940/*
54ceac45 941 * Clone an NFS4 server record on xdev traversal (FSID-change)
f7b422b1 942 */
54ceac45
DH
943static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
944 const char *dev_name, void *raw_data,
945 struct vfsmount *mnt)
f7b422b1 946{
54ceac45
DH
947 struct nfs_clone_mount *data = raw_data;
948 struct super_block *s;
949 struct nfs_server *server;
950 struct dentry *mntroot;
951 int error;
f7b422b1 952
54ceac45 953 dprintk("--> nfs4_xdev_get_sb()\n");
f7b422b1 954
54ceac45
DH
955 /* create a new volume representation */
956 server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
957 if (IS_ERR(server)) {
958 error = PTR_ERR(server);
959 goto out_err_noserver;
f7b422b1 960 }
f7b422b1 961
54ceac45
DH
962 /* Get a superblock - note that we may end up sharing one that already exists */
963 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
964 if (IS_ERR(s)) {
965 error = PTR_ERR(s);
966 goto out_err_nosb;
f7b422b1 967 }
f7b422b1 968
54ceac45
DH
969 if (s->s_fs_info != server) {
970 nfs_free_server(server);
971 server = NULL;
972 }
f7b422b1 973
54ceac45
DH
974 if (!s->s_root) {
975 /* initial superblock/root creation */
976 s->s_flags = flags;
977 nfs4_clone_super(s, data->sb);
978 }
f7b422b1 979
54ceac45
DH
980 mntroot = nfs4_get_root(s, data->fh);
981 if (IS_ERR(mntroot)) {
982 error = PTR_ERR(mntroot);
983 goto error_splat_super;
984 }
f7b422b1 985
54ceac45
DH
986 s->s_flags |= MS_ACTIVE;
987 mnt->mnt_sb = s;
988 mnt->mnt_root = mntroot;
989
990 dprintk("<-- nfs4_xdev_get_sb() = 0\n");
991 return 0;
992
993out_err_nosb:
994 nfs_free_server(server);
995out_err_noserver:
996 dprintk("<-- nfs4_xdev_get_sb() = %d [error]\n", error);
997 return error;
998
999error_splat_super:
1000 up_write(&s->s_umount);
1001 deactivate_super(s);
1002 dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error);
1003 return error;
f7b422b1
DH
1004}
1005
54ceac45
DH
1006/*
1007 * Create an NFS4 server record on referral traversal
1008 */
1009static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
1010 const char *dev_name, void *raw_data,
1011 struct vfsmount *mnt)
f7b422b1
DH
1012{
1013 struct nfs_clone_mount *data = raw_data;
54ceac45
DH
1014 struct super_block *s;
1015 struct nfs_server *server;
1016 struct dentry *mntroot;
1017 struct nfs_fh mntfh;
1018 int error;
1019
1020 dprintk("--> nfs4_referral_get_sb()\n");
1021
1022 /* create a new volume representation */
1023 server = nfs4_create_referral_server(data, &mntfh);
1024 if (IS_ERR(server)) {
1025 error = PTR_ERR(server);
1026 goto out_err_noserver;
1027 }
1028
1029 /* Get a superblock - note that we may end up sharing one that already exists */
1030 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
1031 if (IS_ERR(s)) {
1032 error = PTR_ERR(s);
1033 goto out_err_nosb;
1034 }
1035
1036 if (s->s_fs_info != server) {
1037 nfs_free_server(server);
1038 server = NULL;
1039 }
1040
1041 if (!s->s_root) {
1042 /* initial superblock/root creation */
1043 s->s_flags = flags;
1044 nfs4_fill_super(s);
1045 }
1046
1047 mntroot = nfs4_get_root(s, data->fh);
1048 if (IS_ERR(mntroot)) {
1049 error = PTR_ERR(mntroot);
1050 goto error_splat_super;
1051 }
1052
1053 s->s_flags |= MS_ACTIVE;
1054 mnt->mnt_sb = s;
1055 mnt->mnt_root = mntroot;
1056
1057 dprintk("<-- nfs4_referral_get_sb() = 0\n");
1058 return 0;
1059
1060out_err_nosb:
1061 nfs_free_server(server);
1062out_err_noserver:
1063 dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error);
1064 return error;
1065
1066error_splat_super:
1067 up_write(&s->s_umount);
1068 deactivate_super(s);
1069 dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error);
1070 return error;
f7b422b1
DH
1071}
1072
54ceac45 1073#endif /* CONFIG_NFS_V4 */