Blame view

fs/nfs/super.c 77 KB
f7b422b17   David Howells   NFS: Split fs/nfs...
1
2
3
4
5
6
7
  /*
   *  linux/fs/nfs/super.c
   *
   *  Copyright (C) 1992  Rick Sladkey
   *
   *  nfs superblock handling functions
   *
526719ba5   Alan Cox   Switch to a valid...
8
   *  Modularised by Alan Cox <alan@lxorguk.ukuu.org.uk>, while hacking some
f7b422b17   David Howells   NFS: Split fs/nfs...
9
10
11
12
13
14
15
   *  experimental NFS changes. Modularisation taken straight from SYS5 fs.
   *
   *  Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
   *  J.S.Peatfield@damtp.cam.ac.uk
   *
   *  Split from inode.c by David Howells <dhowells@redhat.com>
   *
54ceac451   David Howells   NFS: Share NFS su...
16
17
18
19
20
   * - superblocks are indexed on server only - all inodes, dentries, etc. associated with a
   *   particular server are held in the same superblock
   * - NFS superblocks can have several effective roots to the dentry tree
   * - directory type roots are spliced into the tree when a path from one root reaches the root
   *   of another (see nfs_lookup())
f7b422b17   David Howells   NFS: Split fs/nfs...
21
   */
f7b422b17   David Howells   NFS: Split fs/nfs...
22
23
24
25
26
27
28
29
30
31
32
33
34
  #include <linux/module.h>
  #include <linux/init.h>
  
  #include <linux/time.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
  #include <linux/string.h>
  #include <linux/stat.h>
  #include <linux/errno.h>
  #include <linux/unistd.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/sunrpc/stats.h>
  #include <linux/sunrpc/metrics.h>
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
35
  #include <linux/sunrpc/xprtsock.h>
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
36
  #include <linux/sunrpc/xprtrdma.h>
f7b422b17   David Howells   NFS: Split fs/nfs...
37
38
39
40
  #include <linux/nfs_fs.h>
  #include <linux/nfs_mount.h>
  #include <linux/nfs4_mount.h>
  #include <linux/lockd/bind.h>
f7b422b17   David Howells   NFS: Split fs/nfs...
41
42
  #include <linux/seq_file.h>
  #include <linux/mount.h>
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
43
  #include <linux/namei.h>
f7b422b17   David Howells   NFS: Split fs/nfs...
44
45
46
  #include <linux/nfs_idmap.h>
  #include <linux/vfs.h>
  #include <linux/inet.h>
fd00a8ff8   Chuck Lever   NFS: Add support ...
47
  #include <linux/in6.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
48
  #include <linux/slab.h>
fd00a8ff8   Chuck Lever   NFS: Add support ...
49
  #include <net/ipv6.h>
d8e7748ab   Chuck Lever   NFS: handle inter...
50
  #include <linux/netdevice.h>
f7b422b17   David Howells   NFS: Split fs/nfs...
51
  #include <linux/nfs_xdr.h>
b5d5dfbd5   Adrian Bunk   [PATCH] include/l...
52
  #include <linux/magic.h>
bf0fd7680   Chuck Lever   NFS: Add enums an...
53
  #include <linux/parser.h>
f7b422b17   David Howells   NFS: Split fs/nfs...
54
55
56
57
58
59
60
61
62
  
  #include <asm/system.h>
  #include <asm/uaccess.h>
  
  #include "nfs4_fs.h"
  #include "callback.h"
  #include "delegation.h"
  #include "iostat.h"
  #include "internal.h"
08734048b   David Howells   NFS: Define and c...
63
  #include "fscache.h"
ae50c0b5c   J. Bruce Fields   pnfs: client stats
64
  #include "pnfs.h"
f7b422b17   David Howells   NFS: Split fs/nfs...
65
66
  
  #define NFSDBG_FACILITY		NFSDBG_VFS
1e657bd51   Paulius Zaleckas   Regression: fix m...
67
68
69
70
71
  #ifdef CONFIG_NFS_V3
  #define NFS_DEFAULT_VERSION 3
  #else
  #define NFS_DEFAULT_VERSION 2
  #endif
bf0fd7680   Chuck Lever   NFS: Add enums an...
72
73
74
  enum {
  	/* Mount options that take no arguments */
  	Opt_soft, Opt_hard,
bf0fd7680   Chuck Lever   NFS: Add enums an...
75
76
77
78
  	Opt_posix, Opt_noposix,
  	Opt_cto, Opt_nocto,
  	Opt_ac, Opt_noac,
  	Opt_lock, Opt_nolock,
764302ccb   Chuck Lever   NFS: Allow the "n...
79
  	Opt_v2, Opt_v3, Opt_v4,
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
80
  	Opt_udp, Opt_tcp, Opt_rdma,
bf0fd7680   Chuck Lever   NFS: Add enums an...
81
82
  	Opt_acl, Opt_noacl,
  	Opt_rdirplus, Opt_nordirplus,
75180df2e   Trond Myklebust   NFS: Add the moun...
83
  	Opt_sharecache, Opt_nosharecache,
d740351bf   Chuck Lever   NFS: add "[no]res...
84
  	Opt_resvport, Opt_noresvport,
b797cac74   David Howells   NFS: Add mount op...
85
  	Opt_fscache, Opt_nofscache,
bf0fd7680   Chuck Lever   NFS: Add enums an...
86
87
88
89
90
91
92
93
94
95
  
  	/* Mount options that take integer arguments */
  	Opt_port,
  	Opt_rsize, Opt_wsize, Opt_bsize,
  	Opt_timeo, Opt_retrans,
  	Opt_acregmin, Opt_acregmax,
  	Opt_acdirmin, Opt_acdirmax,
  	Opt_actimeo,
  	Opt_namelen,
  	Opt_mountport,
e887cbcf9   Chuck Lever   NFS: Remove suppo...
96
  	Opt_mountvers,
ad879cef8   Chuck Lever   NFS: Remove suppo...
97
  	Opt_nfsvers,
3fd5be9e1   Mike Sager   nfs41: add mount ...
98
  	Opt_minorversion,
bf0fd7680   Chuck Lever   NFS: Add enums an...
99
100
  
  	/* Mount options that take string arguments */
338320345   Chuck Lever   NFS: Remove the N...
101
  	Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
0ac83779f   Chuck Lever   NFS: Add new 'mou...
102
  	Opt_addr, Opt_mountaddr, Opt_clientaddr,
7973c1f15   Trond Myklebust   NFS: Add mount op...
103
  	Opt_lookupcache,
b797cac74   David Howells   NFS: Add mount op...
104
  	Opt_fscache_uniq,
5eebde232   Suresh Jayaraman   nfs: introduce mo...
105
  	Opt_local_lock,
bf0fd7680   Chuck Lever   NFS: Add enums an...
106

f45663ce5   Chuck Lever   NFS: Allow either...
107
108
  	/* Special mount options */
  	Opt_userspace, Opt_deprecated, Opt_sloppy,
bf0fd7680   Chuck Lever   NFS: Add enums an...
109
110
111
  
  	Opt_err
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
112
  static const match_table_t nfs_mount_option_tokens = {
bf0fd7680   Chuck Lever   NFS: Add enums an...
113
114
  	{ Opt_userspace, "bg" },
  	{ Opt_userspace, "fg" },
ecbb3845d   Chuck Lever   NFS: Allow any va...
115
  	{ Opt_userspace, "retry=%s" },
f45663ce5   Chuck Lever   NFS: Allow either...
116
  	{ Opt_sloppy, "sloppy" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
117
118
  	{ Opt_soft, "soft" },
  	{ Opt_hard, "hard" },
d33e4dfea   Chuck Lever   NFS: Treat "intr"...
119
120
  	{ Opt_deprecated, "intr" },
  	{ Opt_deprecated, "nointr" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
121
122
123
124
125
126
127
128
129
130
  	{ Opt_posix, "posix" },
  	{ Opt_noposix, "noposix" },
  	{ Opt_cto, "cto" },
  	{ Opt_nocto, "nocto" },
  	{ Opt_ac, "ac" },
  	{ Opt_noac, "noac" },
  	{ Opt_lock, "lock" },
  	{ Opt_nolock, "nolock" },
  	{ Opt_v2, "v2" },
  	{ Opt_v3, "v3" },
764302ccb   Chuck Lever   NFS: Allow the "n...
131
  	{ Opt_v4, "v4" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
132
133
  	{ Opt_udp, "udp" },
  	{ Opt_tcp, "tcp" },
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
134
  	{ Opt_rdma, "rdma" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
135
136
137
138
  	{ Opt_acl, "acl" },
  	{ Opt_noacl, "noacl" },
  	{ Opt_rdirplus, "rdirplus" },
  	{ Opt_nordirplus, "nordirplus" },
75180df2e   Trond Myklebust   NFS: Add the moun...
139
140
  	{ Opt_sharecache, "sharecache" },
  	{ Opt_nosharecache, "nosharecache" },
d740351bf   Chuck Lever   NFS: add "[no]res...
141
142
  	{ Opt_resvport, "resvport" },
  	{ Opt_noresvport, "noresvport" },
b797cac74   David Howells   NFS: Add mount op...
143
  	{ Opt_fscache, "fsc" },
b797cac74   David Howells   NFS: Add mount op...
144
  	{ Opt_nofscache, "nofsc" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
145

a5a16bae7   Chuck Lever   NFS: More "sloppy...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  	{ Opt_port, "port=%s" },
  	{ Opt_rsize, "rsize=%s" },
  	{ Opt_wsize, "wsize=%s" },
  	{ Opt_bsize, "bsize=%s" },
  	{ Opt_timeo, "timeo=%s" },
  	{ Opt_retrans, "retrans=%s" },
  	{ Opt_acregmin, "acregmin=%s" },
  	{ Opt_acregmax, "acregmax=%s" },
  	{ Opt_acdirmin, "acdirmin=%s" },
  	{ Opt_acdirmax, "acdirmax=%s" },
  	{ Opt_actimeo, "actimeo=%s" },
  	{ Opt_namelen, "namlen=%s" },
  	{ Opt_mountport, "mountport=%s" },
  	{ Opt_mountvers, "mountvers=%s" },
  	{ Opt_nfsvers, "nfsvers=%s" },
  	{ Opt_nfsvers, "vers=%s" },
f3f4f4ed2   Chuck Lever   NFS: Fix up new m...
162
  	{ Opt_minorversion, "minorversion=%s" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
163
164
165
166
167
168
  
  	{ Opt_sec, "sec=%s" },
  	{ Opt_proto, "proto=%s" },
  	{ Opt_mountproto, "mountproto=%s" },
  	{ Opt_addr, "addr=%s" },
  	{ Opt_clientaddr, "clientaddr=%s" },
338320345   Chuck Lever   NFS: Remove the N...
169
  	{ Opt_mounthost, "mounthost=%s" },
0ac83779f   Chuck Lever   NFS: Add new 'mou...
170
  	{ Opt_mountaddr, "mountaddr=%s" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
171

7973c1f15   Trond Myklebust   NFS: Add mount op...
172
  	{ Opt_lookupcache, "lookupcache=%s" },
a6d5ff64b   Chuck Lever   NFS: Clean up fsc...
173
  	{ Opt_fscache_uniq, "fsc=%s" },
5eebde232   Suresh Jayaraman   nfs: introduce mo...
174
  	{ Opt_local_lock, "local_lock=%s" },
7973c1f15   Trond Myklebust   NFS: Add mount op...
175

bf0fd7680   Chuck Lever   NFS: Add enums an...
176
177
178
179
  	{ Opt_err, NULL }
  };
  
  enum {
ee671b016   Jeff Layton   NFS: convert prot...
180
  	Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma,
bf0fd7680   Chuck Lever   NFS: Add enums an...
181
182
183
  
  	Opt_xprt_err
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
184
  static const match_table_t nfs_xprt_protocol_tokens = {
bf0fd7680   Chuck Lever   NFS: Add enums an...
185
  	{ Opt_xprt_udp, "udp" },
ee671b016   Jeff Layton   NFS: convert prot...
186
  	{ Opt_xprt_udp6, "udp6" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
187
  	{ Opt_xprt_tcp, "tcp" },
ee671b016   Jeff Layton   NFS: convert prot...
188
  	{ Opt_xprt_tcp6, "tcp6" },
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
189
  	{ Opt_xprt_rdma, "rdma" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
190
191
192
193
194
195
196
197
198
199
200
201
  
  	{ Opt_xprt_err, NULL }
  };
  
  enum {
  	Opt_sec_none, Opt_sec_sys,
  	Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
  	Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp,
  	Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp,
  
  	Opt_sec_err
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
202
  static const match_table_t nfs_secflavor_tokens = {
bf0fd7680   Chuck Lever   NFS: Add enums an...
203
204
205
206
207
208
209
210
211
212
213
  	{ Opt_sec_none, "none" },
  	{ Opt_sec_none, "null" },
  	{ Opt_sec_sys, "sys" },
  
  	{ Opt_sec_krb5, "krb5" },
  	{ Opt_sec_krb5i, "krb5i" },
  	{ Opt_sec_krb5p, "krb5p" },
  
  	{ Opt_sec_lkey, "lkey" },
  	{ Opt_sec_lkeyi, "lkeyi" },
  	{ Opt_sec_lkeyp, "lkeyp" },
8d042218b   Olga Kornievskaia   NFS: add missing ...
214
215
216
  	{ Opt_sec_spkm, "spkm3" },
  	{ Opt_sec_spkmi, "spkm3i" },
  	{ Opt_sec_spkmp, "spkm3p" },
bf0fd7680   Chuck Lever   NFS: Add enums an...
217
218
  	{ Opt_sec_err, NULL }
  };
7973c1f15   Trond Myklebust   NFS: Add mount op...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  enum {
  	Opt_lookupcache_all, Opt_lookupcache_positive,
  	Opt_lookupcache_none,
  
  	Opt_lookupcache_err
  };
  
  static match_table_t nfs_lookupcache_tokens = {
  	{ Opt_lookupcache_all, "all" },
  	{ Opt_lookupcache_positive, "pos" },
  	{ Opt_lookupcache_positive, "positive" },
  	{ Opt_lookupcache_none, "none" },
  
  	{ Opt_lookupcache_err, NULL }
  };
5eebde232   Suresh Jayaraman   nfs: introduce mo...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  enum {
  	Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
  	Opt_local_lock_none,
  
  	Opt_local_lock_err
  };
  
  static match_table_t nfs_local_lock_tokens = {
  	{ Opt_local_lock_all, "all" },
  	{ Opt_local_lock_flock, "flock" },
  	{ Opt_local_lock_posix, "posix" },
  	{ Opt_local_lock_none, "none" },
  
  	{ Opt_local_lock_err, NULL }
  };
bf0fd7680   Chuck Lever   NFS: Add enums an...
249

42faad996   Al Viro   [PATCH] restore s...
250
  static void nfs_umount_begin(struct super_block *);
816724e65   Trond Myklebust   Merge branch 'mas...
251
  static int  nfs_statfs(struct dentry *, struct kstatfs *);
34c80b1d9   Al Viro   vfs: switch ->sho...
252
  static int  nfs_show_options(struct seq_file *, struct dentry *);
d861c630e   Al Viro   vfs: switch ->sho...
253
  static int  nfs_show_devname(struct seq_file *, struct dentry *);
a6322de67   Al Viro   vfs: switch ->sho...
254
  static int  nfs_show_path(struct seq_file *, struct dentry *);
64132379d   Al Viro   vfs: switch ->sho...
255
  static int  nfs_show_stats(struct seq_file *, struct dentry *);
011949811   Al Viro   nfs: switch NFS f...
256
257
  static struct dentry *nfs_fs_mount(struct file_system_type *,
  		int, const char *, void *);
31f43471e   Al Viro   convert simple ca...
258
259
  static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type,
  		int flags, const char *dev_name, void *raw_data);
387c149b5   Trond Myklebust   NFS: Fix a umount...
260
  static void nfs_put_super(struct super_block *);
f7b422b17   David Howells   NFS: Split fs/nfs...
261
  static void nfs_kill_super(struct super_block *);
48b605f83   Jeff Layton   NFS: implement op...
262
  static int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
f7b422b17   David Howells   NFS: Split fs/nfs...
263
264
265
266
  
  static struct file_system_type nfs_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "nfs",
011949811   Al Viro   nfs: switch NFS f...
267
  	.mount		= nfs_fs_mount,
f7b422b17   David Howells   NFS: Split fs/nfs...
268
  	.kill_sb	= nfs_kill_super,
349457ccf   Mark Fasheh   [PATCH] Allow fil...
269
  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b17   David Howells   NFS: Split fs/nfs...
270
  };
54ceac451   David Howells   NFS: Share NFS su...
271
  struct file_system_type nfs_xdev_fs_type = {
f7b422b17   David Howells   NFS: Split fs/nfs...
272
273
  	.owner		= THIS_MODULE,
  	.name		= "nfs",
31f43471e   Al Viro   convert simple ca...
274
  	.mount		= nfs_xdev_mount,
f7b422b17   David Howells   NFS: Split fs/nfs...
275
  	.kill_sb	= nfs_kill_super,
349457ccf   Mark Fasheh   [PATCH] Allow fil...
276
  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b17   David Howells   NFS: Split fs/nfs...
277
  };
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
278
  static const struct super_operations nfs_sops = {
f7b422b17   David Howells   NFS: Split fs/nfs...
279
280
281
  	.alloc_inode	= nfs_alloc_inode,
  	.destroy_inode	= nfs_destroy_inode,
  	.write_inode	= nfs_write_inode,
387c149b5   Trond Myklebust   NFS: Fix a umount...
282
  	.put_super	= nfs_put_super,
f7b422b17   David Howells   NFS: Split fs/nfs...
283
  	.statfs		= nfs_statfs,
b57922d97   Al Viro   convert remaining...
284
  	.evict_inode	= nfs_evict_inode,
f7b422b17   David Howells   NFS: Split fs/nfs...
285
286
  	.umount_begin	= nfs_umount_begin,
  	.show_options	= nfs_show_options,
c7f404b40   Al Viro   vfs: new superblo...
287
288
  	.show_devname	= nfs_show_devname,
  	.show_path	= nfs_show_path,
f7b422b17   David Howells   NFS: Split fs/nfs...
289
  	.show_stats	= nfs_show_stats,
48b605f83   Jeff Layton   NFS: implement op...
290
  	.remount_fs	= nfs_remount,
f7b422b17   David Howells   NFS: Split fs/nfs...
291
292
293
  };
  
  #ifdef CONFIG_NFS_V4
7630c852e   Chuck Lever   NFS: Refactor NFS...
294
295
  static int nfs4_validate_text_mount_data(void *options,
  	struct nfs_parsed_mount_data *args, const char *dev_name);
011949811   Al Viro   nfs: switch NFS f...
296
297
298
299
  static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
  	struct nfs_parsed_mount_data *data);
  static struct dentry *nfs4_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *raw_data);
31f43471e   Al Viro   convert simple ca...
300
301
302
303
  static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *raw_data);
  static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *raw_data);
011949811   Al Viro   nfs: switch NFS f...
304
305
  static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *raw_data);
31f43471e   Al Viro   convert simple ca...
306
307
  static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *raw_data);
f7b422b17   David Howells   NFS: Split fs/nfs...
308
309
310
311
312
  static void nfs4_kill_super(struct super_block *sb);
  
  static struct file_system_type nfs4_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "nfs4",
011949811   Al Viro   nfs: switch NFS f...
313
  	.mount		= nfs4_mount,
f7b422b17   David Howells   NFS: Split fs/nfs...
314
  	.kill_sb	= nfs4_kill_super,
349457ccf   Mark Fasheh   [PATCH] Allow fil...
315
  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b17   David Howells   NFS: Split fs/nfs...
316
  };
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
317
318
319
  static struct file_system_type nfs4_remote_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "nfs4",
31f43471e   Al Viro   convert simple ca...
320
  	.mount		= nfs4_remote_mount,
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
321
322
323
  	.kill_sb	= nfs4_kill_super,
  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
  };
54ceac451   David Howells   NFS: Share NFS su...
324
  struct file_system_type nfs4_xdev_fs_type = {
f7b422b17   David Howells   NFS: Split fs/nfs...
325
326
  	.owner		= THIS_MODULE,
  	.name		= "nfs4",
31f43471e   Al Viro   convert simple ca...
327
  	.mount		= nfs4_xdev_mount,
f7b422b17   David Howells   NFS: Split fs/nfs...
328
  	.kill_sb	= nfs4_kill_super,
349457ccf   Mark Fasheh   [PATCH] Allow fil...
329
  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b17   David Howells   NFS: Split fs/nfs...
330
  };
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
331
332
333
  static struct file_system_type nfs4_remote_referral_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "nfs4",
31f43471e   Al Viro   convert simple ca...
334
  	.mount		= nfs4_remote_referral_mount,
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
335
336
337
  	.kill_sb	= nfs4_kill_super,
  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
  };
54ceac451   David Howells   NFS: Share NFS su...
338
  struct file_system_type nfs4_referral_fs_type = {
f7b422b17   David Howells   NFS: Split fs/nfs...
339
340
  	.owner		= THIS_MODULE,
  	.name		= "nfs4",
011949811   Al Viro   nfs: switch NFS f...
341
  	.mount		= nfs4_referral_mount,
f7b422b17   David Howells   NFS: Split fs/nfs...
342
  	.kill_sb	= nfs4_kill_super,
349457ccf   Mark Fasheh   [PATCH] Allow fil...
343
  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
f7b422b17   David Howells   NFS: Split fs/nfs...
344
  };
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
345
  static const struct super_operations nfs4_sops = {
f7b422b17   David Howells   NFS: Split fs/nfs...
346
347
348
  	.alloc_inode	= nfs_alloc_inode,
  	.destroy_inode	= nfs_destroy_inode,
  	.write_inode	= nfs_write_inode,
387c149b5   Trond Myklebust   NFS: Fix a umount...
349
  	.put_super	= nfs_put_super,
f7b422b17   David Howells   NFS: Split fs/nfs...
350
  	.statfs		= nfs_statfs,
b57922d97   Al Viro   convert remaining...
351
  	.evict_inode	= nfs4_evict_inode,
f7b422b17   David Howells   NFS: Split fs/nfs...
352
353
  	.umount_begin	= nfs_umount_begin,
  	.show_options	= nfs_show_options,
c7f404b40   Al Viro   vfs: new superblo...
354
355
  	.show_devname	= nfs_show_devname,
  	.show_path	= nfs_show_path,
f7b422b17   David Howells   NFS: Split fs/nfs...
356
  	.show_stats	= nfs_show_stats,
48b605f83   Jeff Layton   NFS: implement op...
357
  	.remount_fs	= nfs_remount,
f7b422b17   David Howells   NFS: Split fs/nfs...
358
359
  };
  #endif
8e1f936b7   Rusty Russell   mm: clean up and ...
360
361
362
363
  static struct shrinker acl_shrinker = {
  	.shrink		= nfs_access_cache_shrinker,
  	.seeks		= DEFAULT_SEEKS,
  };
979df72e6   Trond Myklebust   NFS: Add an ACCES...
364

f7b422b17   David Howells   NFS: Split fs/nfs...
365
366
367
368
369
370
371
372
373
374
  /*
   * Register the NFS filesystems
   */
  int __init register_nfs_fs(void)
  {
  	int ret;
  
          ret = register_filesystem(&nfs_fs_type);
  	if (ret < 0)
  		goto error_0;
f7b422b17   David Howells   NFS: Split fs/nfs...
375
376
377
  	ret = nfs_register_sysctl();
  	if (ret < 0)
  		goto error_1;
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
378
  #ifdef CONFIG_NFS_V4
f7b422b17   David Howells   NFS: Split fs/nfs...
379
380
381
382
  	ret = register_filesystem(&nfs4_fs_type);
  	if (ret < 0)
  		goto error_2;
  #endif
8e1f936b7   Rusty Russell   mm: clean up and ...
383
  	register_shrinker(&acl_shrinker);
f7b422b17   David Howells   NFS: Split fs/nfs...
384
385
386
387
388
  	return 0;
  
  #ifdef CONFIG_NFS_V4
  error_2:
  	nfs_unregister_sysctl();
89a09141d   Peter Zijlstra   [PATCH] nfs: fix ...
389
  #endif
f7b422b17   David Howells   NFS: Split fs/nfs...
390
391
  error_1:
  	unregister_filesystem(&nfs_fs_type);
f7b422b17   David Howells   NFS: Split fs/nfs...
392
393
394
395
396
397
398
399
400
  error_0:
  	return ret;
  }
  
  /*
   * Unregister the NFS filesystems
   */
  void __exit unregister_nfs_fs(void)
  {
8e1f936b7   Rusty Russell   mm: clean up and ...
401
  	unregister_shrinker(&acl_shrinker);
f7b422b17   David Howells   NFS: Split fs/nfs...
402
403
  #ifdef CONFIG_NFS_V4
  	unregister_filesystem(&nfs4_fs_type);
f7b422b17   David Howells   NFS: Split fs/nfs...
404
  #endif
49af7ee18   Alexey Dobriyan   nfs: fix oops re ...
405
  	nfs_unregister_sysctl();
f7b422b17   David Howells   NFS: Split fs/nfs...
406
407
  	unregister_filesystem(&nfs_fs_type);
  }
1daef0a86   Trond Myklebust   NFS: Clean up nfs...
408
  void nfs_sb_active(struct super_block *sb)
ef818a28f   Steve Dickson   NFS: Stop sillyna...
409
  {
1daef0a86   Trond Myklebust   NFS: Clean up nfs...
410
  	struct nfs_server *server = NFS_SB(sb);
ef818a28f   Steve Dickson   NFS: Stop sillyna...
411

1daef0a86   Trond Myklebust   NFS: Clean up nfs...
412
413
  	if (atomic_inc_return(&server->active) == 1)
  		atomic_inc(&sb->s_active);
ef818a28f   Steve Dickson   NFS: Stop sillyna...
414
  }
1daef0a86   Trond Myklebust   NFS: Clean up nfs...
415
  void nfs_sb_deactive(struct super_block *sb)
ef818a28f   Steve Dickson   NFS: Stop sillyna...
416
417
  {
  	struct nfs_server *server = NFS_SB(sb);
1daef0a86   Trond Myklebust   NFS: Clean up nfs...
418
419
420
  
  	if (atomic_dec_and_test(&server->active))
  		deactivate_super(sb);
ef818a28f   Steve Dickson   NFS: Stop sillyna...
421
  }
f7b422b17   David Howells   NFS: Split fs/nfs...
422
423
424
  /*
   * Deliver file system statistics to userspace
   */
816724e65   Trond Myklebust   Merge branch 'mas...
425
  static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
f7b422b17   David Howells   NFS: Split fs/nfs...
426
  {
0c7d90cfe   David Howells   NFS: Use the dent...
427
  	struct nfs_server *server = NFS_SB(dentry->d_sb);
f7b422b17   David Howells   NFS: Split fs/nfs...
428
429
  	unsigned char blockbits;
  	unsigned long blockres;
0c7d90cfe   David Howells   NFS: Use the dent...
430
  	struct nfs_fh *fh = NFS_FH(dentry->d_inode);
ca7e9a0df   Trond Myklebust   NFS: Reduce stack...
431
432
433
434
435
436
  	struct nfs_fsstat res;
  	int error = -ENOMEM;
  
  	res.fattr = nfs_alloc_fattr();
  	if (res.fattr == NULL)
  		goto out_err;
f7b422b17   David Howells   NFS: Split fs/nfs...
437

8fa5c000d   David Howells   NFS: Move rpc_ops...
438
  	error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
fbf3fdd24   Menyhart Zoltan   statfs() gives ES...
439
440
441
442
443
444
445
446
447
  	if (unlikely(error == -ESTALE)) {
  		struct dentry *pd_dentry;
  
  		pd_dentry = dget_parent(dentry);
  		if (pd_dentry != NULL) {
  			nfs_zap_caches(pd_dentry->d_inode);
  			dput(pd_dentry);
  		}
  	}
ca7e9a0df   Trond Myklebust   NFS: Reduce stack...
448
  	nfs_free_fattr(res.fattr);
f7b422b17   David Howells   NFS: Split fs/nfs...
449
450
  	if (error < 0)
  		goto out_err;
ca7e9a0df   Trond Myklebust   NFS: Reduce stack...
451

1a0ba9ae4   Amnon Aaronsohn   NFS: statfs error...
452
  	buf->f_type = NFS_SUPER_MAGIC;
f7b422b17   David Howells   NFS: Split fs/nfs...
453
454
455
456
457
458
  
  	/*
  	 * Current versions of glibc do not correctly handle the
  	 * case where f_frsize != f_bsize.  Eventually we want to
  	 * report the value of wtmult in this field.
  	 */
0c7d90cfe   David Howells   NFS: Use the dent...
459
  	buf->f_frsize = dentry->d_sb->s_blocksize;
f7b422b17   David Howells   NFS: Split fs/nfs...
460
461
462
463
464
465
466
467
  
  	/*
  	 * On most *nix systems, f_blocks, f_bfree, and f_bavail
  	 * are reported in units of f_frsize.  Linux hasn't had
  	 * an f_frsize field in its statfs struct until recently,
  	 * thus historically Linux's sys_statfs reports these
  	 * fields in units of f_bsize.
  	 */
0c7d90cfe   David Howells   NFS: Use the dent...
468
469
  	buf->f_bsize = dentry->d_sb->s_blocksize;
  	blockbits = dentry->d_sb->s_blocksize_bits;
f7b422b17   David Howells   NFS: Split fs/nfs...
470
471
472
473
474
475
476
477
478
  	blockres = (1 << blockbits) - 1;
  	buf->f_blocks = (res.tbytes + blockres) >> blockbits;
  	buf->f_bfree = (res.fbytes + blockres) >> blockbits;
  	buf->f_bavail = (res.abytes + blockres) >> blockbits;
  
  	buf->f_files = res.tfiles;
  	buf->f_ffree = res.afiles;
  
  	buf->f_namelen = server->namelen;
1a0ba9ae4   Amnon Aaronsohn   NFS: statfs error...
479

f7b422b17   David Howells   NFS: Split fs/nfs...
480
481
482
  	return 0;
  
   out_err:
3110ff804   Harvey Harrison   nfs: replace rema...
483
484
  	dprintk("%s: statfs error = %d
  ", __func__, -error);
1a0ba9ae4   Amnon Aaronsohn   NFS: statfs error...
485
  	return error;
f7b422b17   David Howells   NFS: Split fs/nfs...
486
  }
7d4e2747a   David Howells   NFS: Fix up split...
487
488
489
  /*
   * Map the security flavour number to a name
   */
81039f1f2   Trond Myklebust   NFS: Display the ...
490
491
  static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
  {
7d4e2747a   David Howells   NFS: Fix up split...
492
  	static const struct {
81039f1f2   Trond Myklebust   NFS: Display the ...
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  		rpc_authflavor_t flavour;
  		const char *str;
  	} sec_flavours[] = {
  		{ RPC_AUTH_NULL, "null" },
  		{ RPC_AUTH_UNIX, "sys" },
  		{ RPC_AUTH_GSS_KRB5, "krb5" },
  		{ RPC_AUTH_GSS_KRB5I, "krb5i" },
  		{ RPC_AUTH_GSS_KRB5P, "krb5p" },
  		{ RPC_AUTH_GSS_LKEY, "lkey" },
  		{ RPC_AUTH_GSS_LKEYI, "lkeyi" },
  		{ RPC_AUTH_GSS_LKEYP, "lkeyp" },
  		{ RPC_AUTH_GSS_SPKM, "spkm" },
  		{ RPC_AUTH_GSS_SPKMI, "spkmi" },
  		{ RPC_AUTH_GSS_SPKMP, "spkmp" },
4d81cd161   Chuck Lever   NFS: Clean-up: fi...
507
  		{ UINT_MAX, "unknown" }
81039f1f2   Trond Myklebust   NFS: Display the ...
508
509
  	};
  	int i;
4d81cd161   Chuck Lever   NFS: Clean-up: fi...
510
  	for (i = 0; sec_flavours[i].flavour != UINT_MAX; i++) {
81039f1f2   Trond Myklebust   NFS: Display the ...
511
512
513
514
515
  		if (sec_flavours[i].flavour == flavour)
  			break;
  	}
  	return sec_flavours[i].str;
  }
ee671b016   Jeff Layton   NFS: convert prot...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
  static void nfs_show_mountd_netid(struct seq_file *m, struct nfs_server *nfss,
  				  int showdefaults)
  {
  	struct sockaddr *sap = (struct sockaddr *) &nfss->mountd_address;
  
  	seq_printf(m, ",mountproto=");
  	switch (sap->sa_family) {
  	case AF_INET:
  		switch (nfss->mountd_protocol) {
  		case IPPROTO_UDP:
  			seq_printf(m, RPCBIND_NETID_UDP);
  			break;
  		case IPPROTO_TCP:
  			seq_printf(m, RPCBIND_NETID_TCP);
  			break;
  		default:
  			if (showdefaults)
  				seq_printf(m, "auto");
  		}
  		break;
  	case AF_INET6:
  		switch (nfss->mountd_protocol) {
  		case IPPROTO_UDP:
  			seq_printf(m, RPCBIND_NETID_UDP6);
  			break;
  		case IPPROTO_TCP:
  			seq_printf(m, RPCBIND_NETID_TCP6);
  			break;
  		default:
  			if (showdefaults)
  				seq_printf(m, "auto");
  		}
  		break;
  	default:
  		if (showdefaults)
  			seq_printf(m, "auto");
  	}
  }
82d101d58   Chuck Lever   NFS: Show most mo...
554
555
556
557
  static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
  				    int showdefaults)
  {
  	struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address;
d5eff1a34   Bryan Schumaker   NFS: Fix /proc/mo...
558
559
  	if (nfss->flags & NFS_MOUNT_LEGACY_INTERFACE)
  		return;
82d101d58   Chuck Lever   NFS: Show most mo...
560
561
562
  	switch (sap->sa_family) {
  	case AF_INET: {
  		struct sockaddr_in *sin = (struct sockaddr_in *)sap;
be8594054   Harvey Harrison   fs: replace NIPQU...
563
  		seq_printf(m, ",mountaddr=%pI4", &sin->sin_addr.s_addr);
82d101d58   Chuck Lever   NFS: Show most mo...
564
565
566
567
  		break;
  	}
  	case AF_INET6: {
  		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
d250e190f   Chuck Lever   NFS: Display comp...
568
  		seq_printf(m, ",mountaddr=%pI6c", &sin6->sin6_addr);
82d101d58   Chuck Lever   NFS: Show most mo...
569
570
571
572
573
574
575
576
577
  		break;
  	}
  	default:
  		if (showdefaults)
  			seq_printf(m, ",mountaddr=unspecified");
  	}
  
  	if (nfss->mountd_version || showdefaults)
  		seq_printf(m, ",mountvers=%u", nfss->mountd_version);
aa6994739   Stanislav Kinsbursky   NFS: suppressing ...
578
579
580
  	if ((nfss->mountd_port &&
  		nfss->mountd_port != (unsigned short)NFS_UNSPEC_PORT) ||
  		showdefaults)
82d101d58   Chuck Lever   NFS: Show most mo...
581
  		seq_printf(m, ",mountport=%u", nfss->mountd_port);
ee671b016   Jeff Layton   NFS: convert prot...
582
  	nfs_show_mountd_netid(m, nfss, showdefaults);
82d101d58   Chuck Lever   NFS: Show most mo...
583
  }
0be8189f2   Trond Myklebust   NFSv4: Ensure tha...
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
  #ifdef CONFIG_NFS_V4
  static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
  				    int showdefaults)
  {
  	struct nfs_client *clp = nfss->nfs_client;
  
  	seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
  	seq_printf(m, ",minorversion=%u", clp->cl_minorversion);
  }
  #else
  static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss,
  				    int showdefaults)
  {
  }
  #endif
f7b422b17   David Howells   NFS: Split fs/nfs...
599
600
601
  /*
   * Describe the mount options in force on this server representation
   */
82d101d58   Chuck Lever   NFS: Show most mo...
602
603
  static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
  				   int showdefaults)
f7b422b17   David Howells   NFS: Split fs/nfs...
604
  {
509de8111   David Howells   NFS: Add extra co...
605
  	static const struct proc_nfs_info {
f7b422b17   David Howells   NFS: Split fs/nfs...
606
  		int flag;
509de8111   David Howells   NFS: Add extra co...
607
608
  		const char *str;
  		const char *nostr;
f7b422b17   David Howells   NFS: Split fs/nfs...
609
610
  	} nfs_info[] = {
  		{ NFS_MOUNT_SOFT, ",soft", ",hard" },
82d101d58   Chuck Lever   NFS: Show most mo...
611
  		{ NFS_MOUNT_POSIX, ",posix", "" },
f7b422b17   David Howells   NFS: Split fs/nfs...
612
613
614
615
  		{ NFS_MOUNT_NOCTO, ",nocto", "" },
  		{ NFS_MOUNT_NOAC, ",noac", "" },
  		{ NFS_MOUNT_NONLM, ",nolock", "" },
  		{ NFS_MOUNT_NOACL, ",noacl", "" },
74dd34e6e   Steve Dickson   NFS: Added suppor...
616
  		{ NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
d740351bf   Chuck Lever   NFS: add "[no]res...
617
618
  		{ NFS_MOUNT_UNSHARED, ",nosharecache", "" },
  		{ NFS_MOUNT_NORESVPORT, ",noresvport", "" },
f7b422b17   David Howells   NFS: Split fs/nfs...
619
620
  		{ 0, NULL, NULL }
  	};
509de8111   David Howells   NFS: Add extra co...
621
  	const struct proc_nfs_info *nfs_infop;
8fa5c000d   David Howells   NFS: Move rpc_ops...
622
  	struct nfs_client *clp = nfss->nfs_client;
82d101d58   Chuck Lever   NFS: Show most mo...
623
  	u32 version = clp->rpc_ops->version;
7c563cc9f   Suresh Jayaraman   nfs: show "local_...
624
  	int local_flock, local_fcntl;
f7b422b17   David Howells   NFS: Split fs/nfs...
625

82d101d58   Chuck Lever   NFS: Show most mo...
626
  	seq_printf(m, ",vers=%u", version);
2d7674322   Chuck Lever   NFS: numeric moun...
627
628
  	seq_printf(m, ",rsize=%u", nfss->rsize);
  	seq_printf(m, ",wsize=%u", nfss->wsize);
82d101d58   Chuck Lever   NFS: Show most mo...
629
630
631
  	if (nfss->bsize != 0)
  		seq_printf(m, ",bsize=%u", nfss->bsize);
  	seq_printf(m, ",namlen=%u", nfss->namelen);
0e0cab744   Chuck Lever   NFS: use document...
632
  	if (nfss->acregmin != NFS_DEF_ACREGMIN*HZ || showdefaults)
2d7674322   Chuck Lever   NFS: numeric moun...
633
  		seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ);
0e0cab744   Chuck Lever   NFS: use document...
634
  	if (nfss->acregmax != NFS_DEF_ACREGMAX*HZ || showdefaults)
2d7674322   Chuck Lever   NFS: numeric moun...
635
  		seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ);
0e0cab744   Chuck Lever   NFS: use document...
636
  	if (nfss->acdirmin != NFS_DEF_ACDIRMIN*HZ || showdefaults)
2d7674322   Chuck Lever   NFS: numeric moun...
637
  		seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ);
0e0cab744   Chuck Lever   NFS: use document...
638
  	if (nfss->acdirmax != NFS_DEF_ACDIRMAX*HZ || showdefaults)
2d7674322   Chuck Lever   NFS: numeric moun...
639
  		seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ);
f7b422b17   David Howells   NFS: Split fs/nfs...
640
641
642
643
644
645
  	for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
  		if (nfss->flags & nfs_infop->flag)
  			seq_puts(m, nfs_infop->str);
  		else
  			seq_puts(m, nfs_infop->nostr);
  	}
56928edd5   \"Talpey, Thomas\   NFS - print accur...
646
  	seq_printf(m, ",proto=%s",
ee671b016   Jeff Layton   NFS: convert prot...
647
  		   rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
82d101d58   Chuck Lever   NFS: Show most mo...
648
649
650
651
652
653
  	if (version == 4) {
  		if (nfss->port != NFS_PORT)
  			seq_printf(m, ",port=%u", nfss->port);
  	} else
  		if (nfss->port)
  			seq_printf(m, ",port=%u", nfss->port);
331702337   Trond Myklebust   NFS: Support per-...
654
655
  	seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ);
  	seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries);
81039f1f2   Trond Myklebust   NFS: Display the ...
656
  	seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
82d101d58   Chuck Lever   NFS: Show most mo...
657
658
659
  
  	if (version != 4)
  		nfs_show_mountd_options(m, nfss, showdefaults);
0be8189f2   Trond Myklebust   NFSv4: Ensure tha...
660
661
  	else
  		nfs_show_nfsv4_options(m, nfss, showdefaults);
82d101d58   Chuck Lever   NFS: Show most mo...
662

b797cac74   David Howells   NFS: Add mount op...
663
664
  	if (nfss->options & NFS_OPTION_FSCACHE)
  		seq_printf(m, ",fsc");
9b00c6431   Patrick J. LoPresti   nfs: Add "lookupc...
665
666
667
668
669
670
671
  
  	if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) {
  		if (nfss->flags & NFS_MOUNT_LOOKUP_CACHE_NONE)
  			seq_printf(m, ",lookupcache=none");
  		else
  			seq_printf(m, ",lookupcache=pos");
  	}
7c563cc9f   Suresh Jayaraman   nfs: show "local_...
672
673
674
675
676
677
678
679
680
681
682
683
  
  	local_flock = nfss->flags & NFS_MOUNT_LOCAL_FLOCK;
  	local_fcntl = nfss->flags & NFS_MOUNT_LOCAL_FCNTL;
  
  	if (!local_flock && !local_fcntl)
  		seq_printf(m, ",local_lock=none");
  	else if (local_flock && local_fcntl)
  		seq_printf(m, ",local_lock=all");
  	else if (local_flock)
  		seq_printf(m, ",local_lock=flock");
  	else
  		seq_printf(m, ",local_lock=posix");
f7b422b17   David Howells   NFS: Split fs/nfs...
684
685
686
687
688
  }
  
  /*
   * Describe the mount options on this VFS mountpoint
   */
34c80b1d9   Al Viro   vfs: switch ->sho...
689
  static int nfs_show_options(struct seq_file *m, struct dentry *root)
f7b422b17   David Howells   NFS: Split fs/nfs...
690
  {
34c80b1d9   Al Viro   vfs: switch ->sho...
691
  	struct nfs_server *nfss = NFS_SB(root->d_sb);
f7b422b17   David Howells   NFS: Split fs/nfs...
692
693
  
  	nfs_show_mount_options(m, nfss, 0);
5d8515cae   Chuck Lever   NFS: eliminate NI...
694
695
696
  	seq_printf(m, ",addr=%s",
  			rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient,
  							RPC_DISPLAY_ADDR));
f7b422b17   David Howells   NFS: Split fs/nfs...
697
698
699
  
  	return 0;
  }
45402c38e   H Hartley Sweeten   nfs/super.c: loca...
700
701
  
  #ifdef CONFIG_NFS_V4
ae50c0b5c   J. Bruce Fields   pnfs: client stats
702
  #ifdef CONFIG_NFS_V4_1
45402c38e   H Hartley Sweeten   nfs/super.c: loca...
703
  static void show_sessions(struct seq_file *m, struct nfs_server *server)
ae50c0b5c   J. Bruce Fields   pnfs: client stats
704
705
706
707
708
  {
  	if (nfs4_has_session(server->nfs_client))
  		seq_printf(m, ",sessions");
  }
  #else
45402c38e   H Hartley Sweeten   nfs/super.c: loca...
709
710
  static void show_sessions(struct seq_file *m, struct nfs_server *server) {}
  #endif
ae50c0b5c   J. Bruce Fields   pnfs: client stats
711
  #endif
45402c38e   H Hartley Sweeten   nfs/super.c: loca...
712
  #ifdef CONFIG_NFS_V4
ae50c0b5c   J. Bruce Fields   pnfs: client stats
713
  #ifdef CONFIG_NFS_V4_1
45402c38e   H Hartley Sweeten   nfs/super.c: loca...
714
  static void show_pnfs(struct seq_file *m, struct nfs_server *server)
ae50c0b5c   J. Bruce Fields   pnfs: client stats
715
716
717
718
719
720
721
  {
  	seq_printf(m, ",pnfs=");
  	if (server->pnfs_curr_ld)
  		seq_printf(m, "%s", server->pnfs_curr_ld->name);
  	else
  		seq_printf(m, "not configured");
  }
45402c38e   H Hartley Sweeten   nfs/super.c: loca...
722
723
724
725
  #else
  static void show_pnfs(struct seq_file *m, struct nfs_server *server) {}
  #endif
  #endif
f7b422b17   David Howells   NFS: Split fs/nfs...
726

d861c630e   Al Viro   vfs: switch ->sho...
727
  static int nfs_show_devname(struct seq_file *m, struct dentry *root)
c7f404b40   Al Viro   vfs: new superblo...
728
729
730
731
732
733
  {
  	char *page = (char *) __get_free_page(GFP_KERNEL);
  	char *devname, *dummy;
  	int err = 0;
  	if (!page)
  		return -ENOMEM;
d861c630e   Al Viro   vfs: switch ->sho...
734
  	devname = nfs_path(&dummy, root, page, PAGE_SIZE);
c7f404b40   Al Viro   vfs: new superblo...
735
736
737
738
739
740
741
742
  	if (IS_ERR(devname))
  		err = PTR_ERR(devname);
  	else
  		seq_escape(m, devname, " \t
  \\");
  	free_page((unsigned long)page);
  	return err;
  }
a6322de67   Al Viro   vfs: switch ->sho...
743
  static int nfs_show_path(struct seq_file *m, struct dentry *dentry)
c7f404b40   Al Viro   vfs: new superblo...
744
745
746
747
  {
  	seq_puts(m, "/");
  	return 0;
  }
f7b422b17   David Howells   NFS: Split fs/nfs...
748
749
750
  /*
   * Present statistical information for this VFS mountpoint
   */
64132379d   Al Viro   vfs: switch ->sho...
751
  static int nfs_show_stats(struct seq_file *m, struct dentry *root)
f7b422b17   David Howells   NFS: Split fs/nfs...
752
753
  {
  	int i, cpu;
64132379d   Al Viro   vfs: switch ->sho...
754
  	struct nfs_server *nfss = NFS_SB(root->d_sb);
f7b422b17   David Howells   NFS: Split fs/nfs...
755
756
757
758
759
760
761
762
763
764
  	struct rpc_auth *auth = nfss->client->cl_auth;
  	struct nfs_iostats totals = { };
  
  	seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
  
  	/*
  	 * Display all mount option settings
  	 */
  	seq_printf(m, "
  \topts:\t");
64132379d   Al Viro   vfs: switch ->sho...
765
766
767
768
  	seq_puts(m, root->d_sb->s_flags & MS_RDONLY ? "ro" : "rw");
  	seq_puts(m, root->d_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
  	seq_puts(m, root->d_sb->s_flags & MS_NOATIME ? ",noatime" : "");
  	seq_puts(m, root->d_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
f7b422b17   David Howells   NFS: Split fs/nfs...
769
770
771
772
773
774
775
776
  	nfs_show_mount_options(m, nfss, 1);
  
  	seq_printf(m, "
  \tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
  
  	seq_printf(m, "
  \tcaps:\t");
  	seq_printf(m, "caps=0x%x", nfss->caps);
2d7674322   Chuck Lever   NFS: numeric moun...
777
778
779
780
  	seq_printf(m, ",wtmult=%u", nfss->wtmult);
  	seq_printf(m, ",dtsize=%u", nfss->dtsize);
  	seq_printf(m, ",bsize=%u", nfss->bsize);
  	seq_printf(m, ",namlen=%u", nfss->namelen);
f7b422b17   David Howells   NFS: Split fs/nfs...
781
782
  
  #ifdef CONFIG_NFS_V4
40c553193   Trond Myklebust   NFS: Remove the r...
783
  	if (nfss->nfs_client->rpc_ops->version == 4) {
f7b422b17   David Howells   NFS: Split fs/nfs...
784
785
786
787
788
  		seq_printf(m, "
  \tnfsv4:\t");
  		seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
  		seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
  		seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
ae50c0b5c   J. Bruce Fields   pnfs: client stats
789
790
  		show_sessions(m, nfss);
  		show_pnfs(m, nfss);
f7b422b17   David Howells   NFS: Split fs/nfs...
791
792
793
794
795
796
  	}
  #endif
  
  	/*
  	 * Display security flavor in effect for this mount
  	 */
2d7674322   Chuck Lever   NFS: numeric moun...
797
798
  	seq_printf(m, "
  \tsec:\tflavor=%u", auth->au_ops->au_flavor);
f7b422b17   David Howells   NFS: Split fs/nfs...
799
  	if (auth->au_flavor)
2d7674322   Chuck Lever   NFS: numeric moun...
800
  		seq_printf(m, ",pseudoflavor=%u", auth->au_flavor);
f7b422b17   David Howells   NFS: Split fs/nfs...
801
802
803
804
805
806
807
808
809
810
811
812
813
814
  
  	/*
  	 * Display superblock I/O counters
  	 */
  	for_each_possible_cpu(cpu) {
  		struct nfs_iostats *stats;
  
  		preempt_disable();
  		stats = per_cpu_ptr(nfss->io_stats, cpu);
  
  		for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
  			totals.events[i] += stats->events[i];
  		for (i = 0; i < __NFSIOS_BYTESMAX; i++)
  			totals.bytes[i] += stats->bytes[i];
6a51091d0   David Howells   NFS: Add some new...
815
816
817
818
  #ifdef CONFIG_NFS_FSCACHE
  		for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
  			totals.fscache[i] += stats->fscache[i];
  #endif
f7b422b17   David Howells   NFS: Split fs/nfs...
819
820
821
822
823
824
825
826
827
828
829
830
  
  		preempt_enable();
  	}
  
  	seq_printf(m, "
  \tevents:\t");
  	for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
  		seq_printf(m, "%lu ", totals.events[i]);
  	seq_printf(m, "
  \tbytes:\t");
  	for (i = 0; i < __NFSIOS_BYTESMAX; i++)
  		seq_printf(m, "%Lu ", totals.bytes[i]);
6a51091d0   David Howells   NFS: Add some new...
831
832
833
834
835
836
837
838
  #ifdef CONFIG_NFS_FSCACHE
  	if (nfss->options & NFS_OPTION_FSCACHE) {
  		seq_printf(m, "
  \tfsc:\t");
  		for (i = 0; i < __NFSIOS_FSCACHEMAX; i++)
  			seq_printf(m, "%Lu ", totals.bytes[i]);
  	}
  #endif
f7b422b17   David Howells   NFS: Split fs/nfs...
839
840
841
842
843
844
845
846
847
848
  	seq_printf(m, "
  ");
  
  	rpc_print_iostats(m, nfss->client);
  
  	return 0;
  }
  
  /*
   * Begin unmount by attempting to remove all automounted mountpoints we added
54ceac451   David Howells   NFS: Share NFS su...
849
   * in response to xdev traversals and referrals
f7b422b17   David Howells   NFS: Split fs/nfs...
850
   */
42faad996   Al Viro   [PATCH] restore s...
851
  static void nfs_umount_begin(struct super_block *sb)
f7b422b17   David Howells   NFS: Split fs/nfs...
852
  {
67e55205e   Alessio Igor Bogani   vfs: umount_begin...
853
  	struct nfs_server *server;
fc6ae3cf4   Trond Myklebust   NFS: Re-enable fo...
854
  	struct rpc_clnt *rpc;
67e55205e   Alessio Igor Bogani   vfs: umount_begin...
855
  	server = NFS_SB(sb);
fc6ae3cf4   Trond Myklebust   NFS: Re-enable fo...
856
857
858
859
860
861
862
  	/* -EIO all pending I/O */
  	rpc = server->client_acl;
  	if (!IS_ERR(rpc))
  		rpc_killall_tasks(rpc);
  	rpc = server->client;
  	if (!IS_ERR(rpc))
  		rpc_killall_tasks(rpc);
f7b422b17   David Howells   NFS: Split fs/nfs...
863
  }
c5811dbdd   Trond Myklebust   NFS: Fix a defaul...
864
  static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int version)
9423a08ad   Chuck Lever   NFS: Add nfs_allo...
865
866
867
868
869
  {
  	struct nfs_parsed_mount_data *data;
  
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
  	if (data) {
9423a08ad   Chuck Lever   NFS: Add nfs_allo...
870
871
872
873
  		data->acregmin		= NFS_DEF_ACREGMIN;
  		data->acregmax		= NFS_DEF_ACREGMAX;
  		data->acdirmin		= NFS_DEF_ACDIRMIN;
  		data->acdirmax		= NFS_DEF_ACDIRMAX;
c5811dbdd   Trond Myklebust   NFS: Fix a defaul...
874
  		data->mount_server.port	= NFS_UNSPEC_PORT;
9423a08ad   Chuck Lever   NFS: Add nfs_allo...
875
  		data->nfs_server.port	= NFS_UNSPEC_PORT;
c5811dbdd   Trond Myklebust   NFS: Fix a defaul...
876
  		data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
9423a08ad   Chuck Lever   NFS: Add nfs_allo...
877
878
  		data->auth_flavors[0]	= RPC_AUTH_UNIX;
  		data->auth_flavor_len	= 1;
c5811dbdd   Trond Myklebust   NFS: Fix a defaul...
879
  		data->version		= version;
9423a08ad   Chuck Lever   NFS: Add nfs_allo...
880
  		data->minorversion	= 0;
8a0d551a5   Jeff Layton   nfs: fix regressi...
881
  		security_init_mnt_opts(&data->lsm_opts);
9423a08ad   Chuck Lever   NFS: Add nfs_allo...
882
883
884
  	}
  	return data;
  }
8a0d551a5   Jeff Layton   nfs: fix regressi...
885
886
887
888
889
890
891
892
893
894
895
896
  static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
  {
  	if (data) {
  		kfree(data->client_address);
  		kfree(data->mount_server.hostname);
  		kfree(data->nfs_server.export_path);
  		kfree(data->nfs_server.hostname);
  		kfree(data->fscache_uniq);
  		security_free_mnt_opts(&data->lsm_opts);
  		kfree(data);
  	}
  }
f7b422b17   David Howells   NFS: Split fs/nfs...
897
  /*
cdcd7f9ab   Chuck Lever   NFS: Verify IPv6 ...
898
899
900
901
   * Sanity-check a server address provided by the mount command.
   *
   * Address family must be initialized, and address must not be
   * the ANY address for that family.
fc50d58fd   Chuck Lever   NFS: Clean-up: Re...
902
903
904
905
906
   */
  static int nfs_verify_server_address(struct sockaddr *addr)
  {
  	switch (addr->sa_family) {
  	case AF_INET: {
cdcd7f9ab   Chuck Lever   NFS: Verify IPv6 ...
907
  		struct sockaddr_in *sa = (struct sockaddr_in *)addr;
e6f1cebf7   Al Viro   [NET] endianness ...
908
  		return sa->sin_addr.s_addr != htonl(INADDR_ANY);
cdcd7f9ab   Chuck Lever   NFS: Verify IPv6 ...
909
910
911
912
  	}
  	case AF_INET6: {
  		struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr;
  		return !ipv6_addr_any(sa);
fc50d58fd   Chuck Lever   NFS: Clean-up: Re...
913
914
  	}
  	}
53a0b9c4c   Chuck Lever   NFS: Replace nfs_...
915
916
  	dfprintk(MOUNT, "NFS: Invalid IP address specified
  ");
fc50d58fd   Chuck Lever   NFS: Clean-up: Re...
917
918
  	return 0;
  }
9412b9277   Chuck Lever   NFS: Refactor mou...
919
  /*
4cfd74fc9   Chuck Lever   NFS: Mount option...
920
921
922
   * Select between a default port value and a user-specified port value.
   * If a zero value is set, then autobind will be used.
   */
f5855fecd   Trond Myklebust   NFS: Fix port and...
923
  static void nfs_set_port(struct sockaddr *sap, int *port,
4cfd74fc9   Chuck Lever   NFS: Mount option...
924
925
  				 const unsigned short default_port)
  {
f5855fecd   Trond Myklebust   NFS: Fix port and...
926
927
  	if (*port == NFS_UNSPEC_PORT)
  		*port = default_port;
4cfd74fc9   Chuck Lever   NFS: Mount option...
928

f5855fecd   Trond Myklebust   NFS: Fix port and...
929
  	rpc_set_port(sap, *port);
4cfd74fc9   Chuck Lever   NFS: Mount option...
930
931
932
  }
  
  /*
259875efe   Trond Myklebust   NFS: set transpor...
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
   * Sanity check the NFS transport protocol.
   *
   */
  static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
  {
  	switch (mnt->nfs_server.protocol) {
  	case XPRT_TRANSPORT_UDP:
  	case XPRT_TRANSPORT_TCP:
  	case XPRT_TRANSPORT_RDMA:
  		break;
  	default:
  		mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
  	}
  }
  
  /*
   * For text based NFSv2/v3 mounts, the mount protocol transport default
   * settings should depend upon the specified NFS transport.
   */
  static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
  {
  	nfs_validate_transport_protocol(mnt);
  
  	if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP ||
  	    mnt->mount_server.protocol == XPRT_TRANSPORT_TCP)
  			return;
  	switch (mnt->nfs_server.protocol) {
  	case XPRT_TRANSPORT_UDP:
  		mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
  		break;
  	case XPRT_TRANSPORT_TCP:
  	case XPRT_TRANSPORT_RDMA:
  		mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
  	}
  }
  
  /*
01060c896   Chuck Lever   NFS: Refactor log...
970
   * Parse the value of the 'sec=' option.
01060c896   Chuck Lever   NFS: Refactor log...
971
972
973
974
975
976
977
978
979
980
981
   */
  static int nfs_parse_security_flavors(char *value,
  				      struct nfs_parsed_mount_data *mnt)
  {
  	substring_t args[MAX_OPT_ARGS];
  
  	dfprintk(MOUNT, "NFS: parsing sec=%s option
  ", value);
  
  	switch (match_token(value, nfs_secflavor_tokens, args)) {
  	case Opt_sec_none:
01060c896   Chuck Lever   NFS: Refactor log...
982
983
984
  		mnt->auth_flavors[0] = RPC_AUTH_NULL;
  		break;
  	case Opt_sec_sys:
01060c896   Chuck Lever   NFS: Refactor log...
985
986
987
  		mnt->auth_flavors[0] = RPC_AUTH_UNIX;
  		break;
  	case Opt_sec_krb5:
01060c896   Chuck Lever   NFS: Refactor log...
988
989
990
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5;
  		break;
  	case Opt_sec_krb5i:
01060c896   Chuck Lever   NFS: Refactor log...
991
992
993
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I;
  		break;
  	case Opt_sec_krb5p:
01060c896   Chuck Lever   NFS: Refactor log...
994
995
996
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P;
  		break;
  	case Opt_sec_lkey:
01060c896   Chuck Lever   NFS: Refactor log...
997
998
999
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY;
  		break;
  	case Opt_sec_lkeyi:
01060c896   Chuck Lever   NFS: Refactor log...
1000
1001
1002
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI;
  		break;
  	case Opt_sec_lkeyp:
01060c896   Chuck Lever   NFS: Refactor log...
1003
1004
1005
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP;
  		break;
  	case Opt_sec_spkm:
01060c896   Chuck Lever   NFS: Refactor log...
1006
1007
1008
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM;
  		break;
  	case Opt_sec_spkmi:
01060c896   Chuck Lever   NFS: Refactor log...
1009
1010
1011
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI;
  		break;
  	case Opt_sec_spkmp:
01060c896   Chuck Lever   NFS: Refactor log...
1012
1013
1014
1015
1016
  		mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP;
  		break;
  	default:
  		return 0;
  	}
9b7160c55   Bryan Schumaker   NFS: don't negoti...
1017
  	mnt->flags |= NFS_MOUNT_SECFLAVOUR;
059f90b32   Chuck Lever   NFS: Fix auth fla...
1018
  	mnt->auth_flavor_len = 1;
01060c896   Chuck Lever   NFS: Refactor log...
1019
1020
  	return 1;
  }
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
  static int nfs_get_option_str(substring_t args[], char **option)
  {
  	kfree(*option);
  	*option = match_strdup(args);
  	return !option;
  }
  
  static int nfs_get_option_ul(substring_t args[], unsigned long *option)
  {
  	int rc;
  	char *string;
  
  	string = match_strdup(args);
  	if (string == NULL)
  		return -ENOMEM;
  	rc = strict_strtoul(string, 10, option);
  	kfree(string);
  
  	return rc;
  }
01060c896   Chuck Lever   NFS: Refactor log...
1041
  /*
bf0fd7680   Chuck Lever   NFS: Add enums an...
1042
   * Error-check and convert a string of mount options from user space into
f45663ce5   Chuck Lever   NFS: Allow either...
1043
1044
1045
   * a data structure.  The whole mount string is processed; bad options are
   * skipped as they are encountered.  If there were no errors, return 1;
   * otherwise return 0 (zero).
bf0fd7680   Chuck Lever   NFS: Add enums an...
1046
1047
1048
1049
   */
  static int nfs_parse_mount_options(char *raw,
  				   struct nfs_parsed_mount_data *mnt)
  {
f9c3a3802   Eric Paris   NFS: use new LSM ...
1050
  	char *p, *string, *secdata;
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1051
  	int rc, sloppy = 0, invalid_option = 0;
ee671b016   Jeff Layton   NFS: convert prot...
1052
1053
  	unsigned short protofamily = AF_UNSPEC;
  	unsigned short mountfamily = AF_UNSPEC;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1054
1055
1056
1057
1058
1059
1060
1061
  
  	if (!raw) {
  		dfprintk(MOUNT, "NFS: mount options string was NULL.
  ");
  		return 1;
  	}
  	dfprintk(MOUNT, "NFS: nfs mount opts='%s'
  ", raw);
f9c3a3802   Eric Paris   NFS: use new LSM ...
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
  	secdata = alloc_secdata();
  	if (!secdata)
  		goto out_nomem;
  
  	rc = security_sb_copy_data(raw, secdata);
  	if (rc)
  		goto out_security_failure;
  
  	rc = security_sb_parse_opts_str(secdata, &mnt->lsm_opts);
  	if (rc)
  		goto out_security_failure;
  
  	free_secdata(secdata);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1075
1076
  	while ((p = strsep(&raw, ",")) != NULL) {
  		substring_t args[MAX_OPT_ARGS];
a5a16bae7   Chuck Lever   NFS: More "sloppy...
1077
1078
  		unsigned long option;
  		int token;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1079
1080
1081
1082
1083
1084
1085
1086
1087
  
  		if (!*p)
  			continue;
  
  		dfprintk(MOUNT, "NFS:   parsing nfs mount option '%s'
  ", p);
  
  		token = match_token(p, nfs_mount_option_tokens, args);
  		switch (token) {
f45663ce5   Chuck Lever   NFS: Allow either...
1088
1089
1090
1091
  
  		/*
  		 * boolean options:  foo/nofoo
  		 */
bf0fd7680   Chuck Lever   NFS: Add enums an...
1092
1093
1094
1095
1096
1097
  		case Opt_soft:
  			mnt->flags |= NFS_MOUNT_SOFT;
  			break;
  		case Opt_hard:
  			mnt->flags &= ~NFS_MOUNT_SOFT;
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  		case Opt_posix:
  			mnt->flags |= NFS_MOUNT_POSIX;
  			break;
  		case Opt_noposix:
  			mnt->flags &= ~NFS_MOUNT_POSIX;
  			break;
  		case Opt_cto:
  			mnt->flags &= ~NFS_MOUNT_NOCTO;
  			break;
  		case Opt_nocto:
  			mnt->flags |= NFS_MOUNT_NOCTO;
  			break;
  		case Opt_ac:
  			mnt->flags &= ~NFS_MOUNT_NOAC;
  			break;
  		case Opt_noac:
  			mnt->flags |= NFS_MOUNT_NOAC;
  			break;
  		case Opt_lock:
  			mnt->flags &= ~NFS_MOUNT_NONLM;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
1118
1119
  			mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
  					NFS_MOUNT_LOCAL_FCNTL);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1120
1121
1122
  			break;
  		case Opt_nolock:
  			mnt->flags |= NFS_MOUNT_NONLM;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
1123
1124
  			mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
  				       NFS_MOUNT_LOCAL_FCNTL);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1125
1126
1127
  			break;
  		case Opt_v2:
  			mnt->flags &= ~NFS_MOUNT_VER3;
764302ccb   Chuck Lever   NFS: Allow the "n...
1128
  			mnt->version = 2;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1129
1130
1131
  			break;
  		case Opt_v3:
  			mnt->flags |= NFS_MOUNT_VER3;
764302ccb   Chuck Lever   NFS: Allow the "n...
1132
  			mnt->version = 3;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1133
  			break;
764302ccb   Chuck Lever   NFS: Allow the "n...
1134
1135
1136
1137
  		case Opt_v4:
  			mnt->flags &= ~NFS_MOUNT_VER3;
  			mnt->version = 4;
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1138
1139
  		case Opt_udp:
  			mnt->flags &= ~NFS_MOUNT_TCP;
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
1140
  			mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1141
1142
1143
  			break;
  		case Opt_tcp:
  			mnt->flags |= NFS_MOUNT_TCP;
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
1144
  			mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1145
  			break;
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
1146
1147
1148
  		case Opt_rdma:
  			mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
  			mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
a67d18f89   Tom Talpey   NFS: load the rpc...
1149
  			xprt_load_transport(p);
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
1150
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
  		case Opt_acl:
  			mnt->flags &= ~NFS_MOUNT_NOACL;
  			break;
  		case Opt_noacl:
  			mnt->flags |= NFS_MOUNT_NOACL;
  			break;
  		case Opt_rdirplus:
  			mnt->flags &= ~NFS_MOUNT_NORDIRPLUS;
  			break;
  		case Opt_nordirplus:
  			mnt->flags |= NFS_MOUNT_NORDIRPLUS;
  			break;
75180df2e   Trond Myklebust   NFS: Add the moun...
1163
1164
1165
1166
1167
1168
  		case Opt_sharecache:
  			mnt->flags &= ~NFS_MOUNT_UNSHARED;
  			break;
  		case Opt_nosharecache:
  			mnt->flags |= NFS_MOUNT_UNSHARED;
  			break;
d740351bf   Chuck Lever   NFS: add "[no]res...
1169
1170
1171
1172
1173
1174
  		case Opt_resvport:
  			mnt->flags &= ~NFS_MOUNT_NORESVPORT;
  			break;
  		case Opt_noresvport:
  			mnt->flags |= NFS_MOUNT_NORESVPORT;
  			break;
b797cac74   David Howells   NFS: Add mount op...
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
  		case Opt_fscache:
  			mnt->options |= NFS_OPTION_FSCACHE;
  			kfree(mnt->fscache_uniq);
  			mnt->fscache_uniq = NULL;
  			break;
  		case Opt_nofscache:
  			mnt->options &= ~NFS_OPTION_FSCACHE;
  			kfree(mnt->fscache_uniq);
  			mnt->fscache_uniq = NULL;
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1185

f45663ce5   Chuck Lever   NFS: Allow either...
1186
1187
1188
  		/*
  		 * options that take numeric values
  		 */
bf0fd7680   Chuck Lever   NFS: Add enums an...
1189
  		case Opt_port:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1190
1191
  			if (nfs_get_option_ul(args, &option) ||
  			    option > USHRT_MAX)
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1192
1193
  				goto out_invalid_value;
  			mnt->nfs_server.port = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1194
1195
  			break;
  		case Opt_rsize:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1196
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1197
1198
  				goto out_invalid_value;
  			mnt->rsize = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1199
1200
  			break;
  		case Opt_wsize:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1201
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1202
1203
  				goto out_invalid_value;
  			mnt->wsize = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1204
1205
  			break;
  		case Opt_bsize:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1206
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1207
1208
  				goto out_invalid_value;
  			mnt->bsize = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1209
1210
  			break;
  		case Opt_timeo:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1211
  			if (nfs_get_option_ul(args, &option) || option == 0)
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1212
1213
  				goto out_invalid_value;
  			mnt->timeo = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1214
1215
  			break;
  		case Opt_retrans:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1216
  			if (nfs_get_option_ul(args, &option) || option == 0)
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1217
1218
  				goto out_invalid_value;
  			mnt->retrans = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1219
1220
  			break;
  		case Opt_acregmin:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1221
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1222
1223
  				goto out_invalid_value;
  			mnt->acregmin = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1224
1225
  			break;
  		case Opt_acregmax:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1226
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1227
1228
  				goto out_invalid_value;
  			mnt->acregmax = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1229
1230
  			break;
  		case Opt_acdirmin:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1231
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1232
1233
  				goto out_invalid_value;
  			mnt->acdirmin = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1234
1235
  			break;
  		case Opt_acdirmax:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1236
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1237
1238
  				goto out_invalid_value;
  			mnt->acdirmax = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1239
1240
  			break;
  		case Opt_actimeo:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1241
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1242
1243
1244
  				goto out_invalid_value;
  			mnt->acregmin = mnt->acregmax =
  			mnt->acdirmin = mnt->acdirmax = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1245
1246
  			break;
  		case Opt_namelen:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1247
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1248
1249
  				goto out_invalid_value;
  			mnt->namlen = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1250
1251
  			break;
  		case Opt_mountport:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1252
1253
  			if (nfs_get_option_ul(args, &option) ||
  			    option > USHRT_MAX)
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1254
1255
  				goto out_invalid_value;
  			mnt->mount_server.port = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1256
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1257
  		case Opt_mountvers:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1258
  			if (nfs_get_option_ul(args, &option) ||
f45663ce5   Chuck Lever   NFS: Allow either...
1259
  			    option < NFS_MNT_VERSION ||
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1260
1261
1262
  			    option > NFS_MNT3_VERSION)
  				goto out_invalid_value;
  			mnt->mount_server.version = option;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1263
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1264
  		case Opt_nfsvers:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1265
  			if (nfs_get_option_ul(args, &option))
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1266
  				goto out_invalid_value;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1267
  			switch (option) {
f45663ce5   Chuck Lever   NFS: Allow either...
1268
  			case NFS2_VERSION:
bf0fd7680   Chuck Lever   NFS: Add enums an...
1269
  				mnt->flags &= ~NFS_MOUNT_VER3;
764302ccb   Chuck Lever   NFS: Allow the "n...
1270
  				mnt->version = 2;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1271
  				break;
f45663ce5   Chuck Lever   NFS: Allow either...
1272
  			case NFS3_VERSION:
bf0fd7680   Chuck Lever   NFS: Add enums an...
1273
  				mnt->flags |= NFS_MOUNT_VER3;
764302ccb   Chuck Lever   NFS: Allow the "n...
1274
1275
  				mnt->version = 3;
  				break;
764302ccb   Chuck Lever   NFS: Allow the "n...
1276
1277
1278
  			case NFS4_VERSION:
  				mnt->flags &= ~NFS_MOUNT_VER3;
  				mnt->version = 4;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1279
1280
  				break;
  			default:
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1281
  				goto out_invalid_value;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1282
1283
  			}
  			break;
3fd5be9e1   Mike Sager   nfs41: add mount ...
1284
  		case Opt_minorversion:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1285
  			if (nfs_get_option_ul(args, &option))
f3f4f4ed2   Chuck Lever   NFS: Fix up new m...
1286
1287
1288
1289
  				goto out_invalid_value;
  			if (option > NFS4_MAX_MINOR_VERSION)
  				goto out_invalid_value;
  			mnt->minorversion = option;
3fd5be9e1   Mike Sager   nfs41: add mount ...
1290
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1291

f45663ce5   Chuck Lever   NFS: Allow either...
1292
1293
1294
  		/*
  		 * options that take text values
  		 */
bf0fd7680   Chuck Lever   NFS: Add enums an...
1295
1296
1297
1298
  		case Opt_sec:
  			string = match_strdup(args);
  			if (string == NULL)
  				goto out_nomem;
01060c896   Chuck Lever   NFS: Refactor log...
1299
  			rc = nfs_parse_security_flavors(string, mnt);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1300
  			kfree(string);
f45663ce5   Chuck Lever   NFS: Allow either...
1301
  			if (!rc) {
f45663ce5   Chuck Lever   NFS: Allow either...
1302
1303
1304
  				dfprintk(MOUNT, "NFS:   unrecognized "
  						"security flavor
  ");
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1305
  				return 0;
f45663ce5   Chuck Lever   NFS: Allow either...
1306
  			}
bf0fd7680   Chuck Lever   NFS: Add enums an...
1307
1308
1309
1310
1311
1312
1313
  			break;
  		case Opt_proto:
  			string = match_strdup(args);
  			if (string == NULL)
  				goto out_nomem;
  			token = match_token(string,
  					    nfs_xprt_protocol_tokens, args);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1314

ee671b016   Jeff Layton   NFS: convert prot...
1315
  			protofamily = AF_INET;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1316
  			switch (token) {
ee671b016   Jeff Layton   NFS: convert prot...
1317
1318
  			case Opt_xprt_udp6:
  				protofamily = AF_INET6;
fdb66ff4a   Chuck Lever   NFS: mount option...
1319
  			case Opt_xprt_udp:
bf0fd7680   Chuck Lever   NFS: Add enums an...
1320
  				mnt->flags &= ~NFS_MOUNT_TCP;
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
1321
  				mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1322
  				break;
ee671b016   Jeff Layton   NFS: convert prot...
1323
1324
  			case Opt_xprt_tcp6:
  				protofamily = AF_INET6;
fdb66ff4a   Chuck Lever   NFS: mount option...
1325
  			case Opt_xprt_tcp:
bf0fd7680   Chuck Lever   NFS: Add enums an...
1326
  				mnt->flags |= NFS_MOUNT_TCP;
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
1327
  				mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1328
  				break;
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
1329
1330
1331
1332
  			case Opt_xprt_rdma:
  				/* vector side protocols to TCP */
  				mnt->flags |= NFS_MOUNT_TCP;
  				mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
a67d18f89   Tom Talpey   NFS: load the rpc...
1333
  				xprt_load_transport(string);
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
1334
  				break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1335
  			default:
f45663ce5   Chuck Lever   NFS: Allow either...
1336
1337
1338
  				dfprintk(MOUNT, "NFS:   unrecognized "
  						"transport protocol
  ");
4223a4a15   Yinghai Lu   nfs: Fix nfs_pars...
1339
  				kfree(string);
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1340
  				return 0;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1341
  			}
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1342
  			kfree(string);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1343
1344
1345
1346
1347
1348
1349
  			break;
  		case Opt_mountproto:
  			string = match_strdup(args);
  			if (string == NULL)
  				goto out_nomem;
  			token = match_token(string,
  					    nfs_xprt_protocol_tokens, args);
d508afb43   Trond Myklebust   NFS: Fix a double...
1350
  			kfree(string);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1351

ee671b016   Jeff Layton   NFS: convert prot...
1352
  			mountfamily = AF_INET;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1353
  			switch (token) {
ee671b016   Jeff Layton   NFS: convert prot...
1354
1355
  			case Opt_xprt_udp6:
  				mountfamily = AF_INET6;
fdb66ff4a   Chuck Lever   NFS: mount option...
1356
  			case Opt_xprt_udp:
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
1357
  				mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1358
  				break;
ee671b016   Jeff Layton   NFS: convert prot...
1359
1360
  			case Opt_xprt_tcp6:
  				mountfamily = AF_INET6;
fdb66ff4a   Chuck Lever   NFS: mount option...
1361
  			case Opt_xprt_tcp:
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
1362
  				mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1363
  				break;
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
1364
  			case Opt_xprt_rdma: /* not used for side protocols */
bf0fd7680   Chuck Lever   NFS: Add enums an...
1365
  			default:
f45663ce5   Chuck Lever   NFS: Allow either...
1366
1367
1368
  				dfprintk(MOUNT, "NFS:   unrecognized "
  						"transport protocol
  ");
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1369
  				return 0;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1370
1371
1372
1373
1374
1375
  			}
  			break;
  		case Opt_addr:
  			string = match_strdup(args);
  			if (string == NULL)
  				goto out_nomem;
53a0b9c4c   Chuck Lever   NFS: Replace nfs_...
1376
1377
1378
1379
1380
  			mnt->nfs_server.addrlen =
  				rpc_pton(string, strlen(string),
  					(struct sockaddr *)
  					&mnt->nfs_server.address,
  					sizeof(mnt->nfs_server.address));
bf0fd7680   Chuck Lever   NFS: Add enums an...
1381
  			kfree(string);
53a0b9c4c   Chuck Lever   NFS: Replace nfs_...
1382
1383
  			if (mnt->nfs_server.addrlen == 0)
  				goto out_invalid_address;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1384
1385
  			break;
  		case Opt_clientaddr:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1386
  			if (nfs_get_option_str(args, &mnt->client_address))
bf0fd7680   Chuck Lever   NFS: Add enums an...
1387
  				goto out_nomem;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1388
  			break;
338320345   Chuck Lever   NFS: Remove the N...
1389
  		case Opt_mounthost:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1390
1391
  			if (nfs_get_option_str(args,
  					       &mnt->mount_server.hostname))
338320345   Chuck Lever   NFS: Remove the N...
1392
  				goto out_nomem;
338320345   Chuck Lever   NFS: Remove the N...
1393
  			break;
0ac83779f   Chuck Lever   NFS: Add new 'mou...
1394
  		case Opt_mountaddr:
bf0fd7680   Chuck Lever   NFS: Add enums an...
1395
1396
1397
  			string = match_strdup(args);
  			if (string == NULL)
  				goto out_nomem;
53a0b9c4c   Chuck Lever   NFS: Replace nfs_...
1398
1399
1400
1401
1402
  			mnt->mount_server.addrlen =
  				rpc_pton(string, strlen(string),
  					(struct sockaddr *)
  					&mnt->mount_server.address,
  					sizeof(mnt->mount_server.address));
bf0fd7680   Chuck Lever   NFS: Add enums an...
1403
  			kfree(string);
53a0b9c4c   Chuck Lever   NFS: Replace nfs_...
1404
1405
  			if (mnt->mount_server.addrlen == 0)
  				goto out_invalid_address;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1406
  			break;
7973c1f15   Trond Myklebust   NFS: Add mount op...
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
  		case Opt_lookupcache:
  			string = match_strdup(args);
  			if (string == NULL)
  				goto out_nomem;
  			token = match_token(string,
  					nfs_lookupcache_tokens, args);
  			kfree(string);
  			switch (token) {
  				case Opt_lookupcache_all:
  					mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
  					break;
  				case Opt_lookupcache_positive:
  					mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
  					mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
  					break;
  				case Opt_lookupcache_none:
  					mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
  					break;
  				default:
7973c1f15   Trond Myklebust   NFS: Add mount op...
1426
1427
1428
  					dfprintk(MOUNT, "NFS:   invalid "
  							"lookupcache argument
  ");
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1429
  					return 0;
7973c1f15   Trond Myklebust   NFS: Add mount op...
1430
1431
  			};
  			break;
a6d5ff64b   Chuck Lever   NFS: Clean up fsc...
1432
  		case Opt_fscache_uniq:
c5cb09b6f   Rob Landley   Cleanup: Factor o...
1433
  			if (nfs_get_option_str(args, &mnt->fscache_uniq))
a6d5ff64b   Chuck Lever   NFS: Clean up fsc...
1434
  				goto out_nomem;
a6d5ff64b   Chuck Lever   NFS: Clean up fsc...
1435
1436
  			mnt->options |= NFS_OPTION_FSCACHE;
  			break;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  		case Opt_local_lock:
  			string = match_strdup(args);
  			if (string == NULL)
  				goto out_nomem;
  			token = match_token(string, nfs_local_lock_tokens,
  					args);
  			kfree(string);
  			switch (token) {
  			case Opt_local_lock_all:
  				mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
  					       NFS_MOUNT_LOCAL_FCNTL);
  				break;
  			case Opt_local_lock_flock:
  				mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
  				break;
  			case Opt_local_lock_posix:
  				mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
  				break;
  			case Opt_local_lock_none:
  				mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
  						NFS_MOUNT_LOCAL_FCNTL);
  				break;
  			default:
  				dfprintk(MOUNT, "NFS:	invalid	"
  						"local_lock argument
  ");
  				return 0;
  			};
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1466

f45663ce5   Chuck Lever   NFS: Allow either...
1467
1468
1469
1470
1471
1472
1473
1474
  		/*
  		 * Special options
  		 */
  		case Opt_sloppy:
  			sloppy = 1;
  			dfprintk(MOUNT, "NFS:   relaxing parsing rules
  ");
  			break;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1475
1476
  		case Opt_userspace:
  		case Opt_deprecated:
d33e4dfea   Chuck Lever   NFS: Treat "intr"...
1477
1478
1479
  			dfprintk(MOUNT, "NFS:   ignoring mount option "
  					"'%s'
  ", p);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1480
1481
1482
  			break;
  
  		default:
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1483
  			invalid_option = 1;
f45663ce5   Chuck Lever   NFS: Allow either...
1484
1485
1486
  			dfprintk(MOUNT, "NFS:   unrecognized mount option "
  					"'%s'
  ", p);
bf0fd7680   Chuck Lever   NFS: Add enums an...
1487
1488
  		}
  	}
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1489
1490
  	if (!sloppy && invalid_option)
  		return 0;
ee671b016   Jeff Layton   NFS: convert prot...
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  	/*
  	 * verify that any proto=/mountproto= options match the address
  	 * familiies in the addr=/mountaddr= options.
  	 */
  	if (protofamily != AF_UNSPEC &&
  	    protofamily != mnt->nfs_server.address.ss_family)
  		goto out_proto_mismatch;
  
  	if (mountfamily != AF_UNSPEC) {
  		if (mnt->mount_server.addrlen) {
  			if (mountfamily != mnt->mount_server.address.ss_family)
  				goto out_mountproto_mismatch;
  		} else {
  			if (mountfamily != mnt->nfs_server.address.ss_family)
  				goto out_mountproto_mismatch;
  		}
  	}
bf0fd7680   Chuck Lever   NFS: Add enums an...
1508
  	return 1;
ee671b016   Jeff Layton   NFS: convert prot...
1509
1510
1511
1512
1513
1514
1515
1516
1517
  out_mountproto_mismatch:
  	printk(KERN_INFO "NFS: mount server address does not match mountproto= "
  			 "option
  ");
  	return 0;
  out_proto_mismatch:
  	printk(KERN_INFO "NFS: server address does not match proto= option
  ");
  	return 0;
53a0b9c4c   Chuck Lever   NFS: Replace nfs_...
1518
1519
1520
1521
  out_invalid_address:
  	printk(KERN_INFO "NFS: bad IP address specified: %s
  ", p);
  	return 0;
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1522
  out_invalid_value:
53a0b9c4c   Chuck Lever   NFS: Replace nfs_...
1523
1524
  	printk(KERN_INFO "NFS: bad mount option value specified: %s
  ", p);
d23c45fd8   Chuck Lever   NFS: Invalid moun...
1525
  	return 0;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1526
1527
1528
1529
  out_nomem:
  	printk(KERN_INFO "NFS: not enough memory to parse option
  ");
  	return 0;
f9c3a3802   Eric Paris   NFS: use new LSM ...
1530
1531
1532
1533
1534
  out_security_failure:
  	free_secdata(secdata);
  	printk(KERN_INFO "NFS: security options invalid: %d
  ", rc);
  	return 0;
bf0fd7680   Chuck Lever   NFS: Add enums an...
1535
1536
1537
  }
  
  /*
ec88f28d1   Chuck Lever   NFS: Use the auth...
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
   * Match the requested auth flavors with the list returned by
   * the server.  Returns zero and sets the mount's authentication
   * flavor on success; returns -EACCES if server does not support
   * the requested flavor.
   */
  static int nfs_walk_authlist(struct nfs_parsed_mount_data *args,
  			     struct nfs_mount_request *request)
  {
  	unsigned int i, j, server_authlist_len = *(request->auth_flav_len);
  
  	/*
5eecfde61   Chuck Lever   NFS: Handle a zer...
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
  	 * Certain releases of Linux's mountd return an empty
  	 * flavor list.  To prevent behavioral regression with
  	 * these servers (ie. rejecting mounts that used to
  	 * succeed), revert to pre-2.6.32 behavior (no checking)
  	 * if the returned flavor list is empty.
  	 */
  	if (server_authlist_len == 0)
  		return 0;
  
  	/*
ec88f28d1   Chuck Lever   NFS: Use the auth...
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
  	 * We avoid sophisticated negotiating here, as there are
  	 * plenty of cases where we can get it wrong, providing
  	 * either too little or too much security.
  	 *
  	 * RFC 2623, section 2.7 suggests we SHOULD prefer the
  	 * flavor listed first.  However, some servers list
  	 * AUTH_NULL first.  Our caller plants AUTH_SYS, the
  	 * preferred default, in args->auth_flavors[0] if user
  	 * didn't specify sec= mount option.
  	 */
  	for (i = 0; i < args->auth_flavor_len; i++)
  		for (j = 0; j < server_authlist_len; j++)
  			if (args->auth_flavors[i] == request->auth_flavs[j]) {
  				dfprintk(MOUNT, "NFS: using auth flavor %d
  ",
  					request->auth_flavs[j]);
  				args->auth_flavors[0] = request->auth_flavs[j];
  				return 0;
  			}
  
  	dfprintk(MOUNT, "NFS: server does not support requested auth flavor
  ");
  	nfs_umount(request);
  	return -EACCES;
  }
  
  /*
0076d7b7b   Chuck Lever   NFS: Introduce ge...
1586
1587
1588
1589
1590
1591
   * Use the remote server's MOUNT service to request the NFS file handle
   * corresponding to the provided path.
   */
  static int nfs_try_mount(struct nfs_parsed_mount_data *args,
  			 struct nfs_fh *root_fh)
  {
ec88f28d1   Chuck Lever   NFS: Use the auth...
1592
1593
  	rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS];
  	unsigned int server_authlist_len = ARRAY_SIZE(server_authlist);
c5d120f8e   Chuck Lever   NFS: introduce nf...
1594
1595
1596
1597
1598
1599
  	struct nfs_mount_request request = {
  		.sap		= (struct sockaddr *)
  						&args->mount_server.address,
  		.dirpath	= args->nfs_server.export_path,
  		.protocol	= args->mount_server.protocol,
  		.fh		= root_fh,
50a737f86   Chuck Lever   NFS: "[no]resvpor...
1600
  		.noresvport	= args->flags & NFS_MOUNT_NORESVPORT,
ec88f28d1   Chuck Lever   NFS: Use the auth...
1601
1602
  		.auth_flav_len	= &server_authlist_len,
  		.auth_flavs	= server_authlist,
c5d120f8e   Chuck Lever   NFS: introduce nf...
1603
  	};
4c5680177   Chuck Lever   NFS: Support non-...
1604
  	int status;
0076d7b7b   Chuck Lever   NFS: Introduce ge...
1605
1606
  
  	if (args->mount_server.version == 0) {
8a6e5deb8   Trond Myklebust   NFS: Get rid of t...
1607
1608
1609
1610
1611
1612
1613
  		switch (args->version) {
  			default:
  				args->mount_server.version = NFS_MNT3_VERSION;
  				break;
  			case 2:
  				args->mount_server.version = NFS_MNT_VERSION;
  		}
0076d7b7b   Chuck Lever   NFS: Introduce ge...
1614
  	}
c5d120f8e   Chuck Lever   NFS: introduce nf...
1615
  	request.version = args->mount_server.version;
0076d7b7b   Chuck Lever   NFS: Introduce ge...
1616

338320345   Chuck Lever   NFS: Remove the N...
1617
  	if (args->mount_server.hostname)
c5d120f8e   Chuck Lever   NFS: introduce nf...
1618
  		request.hostname = args->mount_server.hostname;
338320345   Chuck Lever   NFS: Remove the N...
1619
  	else
c5d120f8e   Chuck Lever   NFS: introduce nf...
1620
  		request.hostname = args->nfs_server.hostname;
338320345   Chuck Lever   NFS: Remove the N...
1621

0076d7b7b   Chuck Lever   NFS: Introduce ge...
1622
1623
1624
  	/*
  	 * Construct the mount server's address.
  	 */
4c5680177   Chuck Lever   NFS: Support non-...
1625
  	if (args->mount_server.address.ss_family == AF_UNSPEC) {
c5d120f8e   Chuck Lever   NFS: introduce nf...
1626
  		memcpy(request.sap, &args->nfs_server.address,
4c5680177   Chuck Lever   NFS: Support non-...
1627
1628
1629
  		       args->nfs_server.addrlen);
  		args->mount_server.addrlen = args->nfs_server.addrlen;
  	}
c5d120f8e   Chuck Lever   NFS: introduce nf...
1630
  	request.salen = args->mount_server.addrlen;
f5855fecd   Trond Myklebust   NFS: Fix port and...
1631
  	nfs_set_port(request.sap, &args->mount_server.port, 0);
0076d7b7b   Chuck Lever   NFS: Introduce ge...
1632
1633
1634
1635
1636
  
  	/*
  	 * Now ask the mount server to map our export path
  	 * to a file handle.
  	 */
c5d120f8e   Chuck Lever   NFS: introduce nf...
1637
  	status = nfs_mount(&request);
ec88f28d1   Chuck Lever   NFS: Use the auth...
1638
1639
1640
1641
1642
1643
  	if (status != 0) {
  		dfprintk(MOUNT, "NFS: unable to mount server %s, error %d
  ",
  				request.hostname, status);
  		return status;
  	}
0076d7b7b   Chuck Lever   NFS: Introduce ge...
1644

ec88f28d1   Chuck Lever   NFS: Use the auth...
1645
1646
1647
1648
1649
1650
  	/*
  	 * MNTv1 (NFSv2) does not support auth flavor negotiation.
  	 */
  	if (args->mount_server.version != NFS_MNT3_VERSION)
  		return 0;
  	return nfs_walk_authlist(args, &request);
0076d7b7b   Chuck Lever   NFS: Introduce ge...
1651
  }
c12bacec4   Rob Landley   cleanup: save 60 ...
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
  /*
   * Split "dev_name" into "hostname:export_path".
   *
   * The leftmost colon demarks the split between the server's hostname
   * and the export path.  If the hostname starts with a left square
   * bracket, then it may contain colons.
   *
   * Note: caller frees hostname and export path, even on error.
   */
  static int nfs_parse_devname(const char *dev_name,
  			     char **hostname, size_t maxnamlen,
  			     char **export_path, size_t maxpathlen)
dc0458982   Chuck Lever   NFS: Use common d...
1664
1665
  {
  	size_t len;
c12bacec4   Rob Landley   cleanup: save 60 ...
1666
  	char *end;
dc0458982   Chuck Lever   NFS: Use common d...
1667

c12bacec4   Rob Landley   cleanup: save 60 ...
1668
1669
1670
1671
  	/* Is the host name protected with square brakcets? */
  	if (*dev_name == '[') {
  		end = strchr(++dev_name, ']');
  		if (end == NULL || end[1] != ':')
dc0458982   Chuck Lever   NFS: Use common d...
1672
  			goto out_bad_devname;
dc0458982   Chuck Lever   NFS: Use common d...
1673

c12bacec4   Rob Landley   cleanup: save 60 ...
1674
1675
1676
1677
  		len = end - dev_name;
  		end++;
  	} else {
  		char *comma;
dc0458982   Chuck Lever   NFS: Use common d...
1678

c12bacec4   Rob Landley   cleanup: save 60 ...
1679
1680
1681
1682
  		end = strchr(dev_name, ':');
  		if (end == NULL)
  			goto out_bad_devname;
  		len = end - dev_name;
d1aa08257   Chuck Lever   NFS: Support raw ...
1683

c12bacec4   Rob Landley   cleanup: save 60 ...
1684
1685
1686
1687
1688
  		/* kill possible hostname list: not supported */
  		comma = strchr(dev_name, ',');
  		if (comma != NULL && comma < end)
  			*comma = 0;
  	}
d1aa08257   Chuck Lever   NFS: Support raw ...
1689

d1aa08257   Chuck Lever   NFS: Support raw ...
1690
1691
1692
1693
  	if (len > maxnamlen)
  		goto out_hostname;
  
  	/* N.B. caller will free nfs_server.hostname in all cases */
c12bacec4   Rob Landley   cleanup: save 60 ...
1694
  	*hostname = kstrndup(dev_name, len, GFP_KERNEL);
d1aa08257   Chuck Lever   NFS: Support raw ...
1695
1696
  	if (*hostname == NULL)
  		goto out_nomem;
c12bacec4   Rob Landley   cleanup: save 60 ...
1697
  	len = strlen(++end);
d1aa08257   Chuck Lever   NFS: Support raw ...
1698
1699
1700
1701
1702
  	if (len > maxpathlen)
  		goto out_path;
  	*export_path = kstrndup(end, len, GFP_KERNEL);
  	if (!*export_path)
  		goto out_nomem;
c12bacec4   Rob Landley   cleanup: save 60 ...
1703
1704
  	dfprintk(MOUNT, "NFS: MNTPATH: '%s'
  ", *export_path);
d1aa08257   Chuck Lever   NFS: Support raw ...
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
  	return 0;
  
  out_bad_devname:
  	dfprintk(MOUNT, "NFS: device name not in host:path format
  ");
  	return -EINVAL;
  
  out_nomem:
  	dfprintk(MOUNT, "NFS: not enough memory to parse device name
  ");
  	return -ENOMEM;
  
  out_hostname:
  	dfprintk(MOUNT, "NFS: server hostname too long
  ");
  	return -ENAMETOOLONG;
  
  out_path:
  	dfprintk(MOUNT, "NFS: export pathname too long
  ");
  	return -ENAMETOOLONG;
  }
  
  /*
54ceac451   David Howells   NFS: Share NFS su...
1729
1730
   * Validate the NFS2/NFS3 mount data
   * - fills in the mount root filehandle
136d558ce   Chuck Lever   NFS: Add final pi...
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
   *
   * For option strings, user space handles the following behaviors:
   *
   * + DNS: mapping server host name to IP address ("addr=" option)
   *
   * + failure mode: how to behave if a mount request can't be handled
   *   immediately ("fg/bg" option)
   *
   * + retry: how often to retry a mount request ("retry=" option)
   *
   * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
   *   mountproto=tcp after mountproto=udp, and so on
f7b422b17   David Howells   NFS: Split fs/nfs...
1743
   */
2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
1744
1745
  static int nfs_validate_mount_data(void *options,
  				   struct nfs_parsed_mount_data *args,
136d558ce   Chuck Lever   NFS: Add final pi...
1746
1747
  				   struct nfs_fh *mntfh,
  				   const char *dev_name)
f7b422b17   David Howells   NFS: Split fs/nfs...
1748
  {
2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
1749
  	struct nfs_mount_data *data = (struct nfs_mount_data *)options;
4cfd74fc9   Chuck Lever   NFS: Mount option...
1750
  	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
136d558ce   Chuck Lever   NFS: Add final pi...
1751

5df36e78d   Chuck Lever   NFS: Clean up nfs...
1752
1753
  	if (data == NULL)
  		goto out_no_data;
f7b422b17   David Howells   NFS: Split fs/nfs...
1754

54ceac451   David Howells   NFS: Share NFS su...
1755
  	switch (data->version) {
5df36e78d   Chuck Lever   NFS: Clean up nfs...
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
  	case 1:
  		data->namlen = 0;
  	case 2:
  		data->bsize = 0;
  	case 3:
  		if (data->flags & NFS_MOUNT_VER3)
  			goto out_no_v3;
  		data->root.size = NFS2_FHSIZE;
  		memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
  	case 4:
  		if (data->flags & NFS_MOUNT_SECFLAVOUR)
  			goto out_no_sec;
  	case 5:
  		memset(data->context, 0, sizeof(data->context));
  	case 6:
b7e244573   Trond Myklebust   NFS: Fix filehand...
1771
1772
1773
  		if (data->flags & NFS_MOUNT_VER3) {
  			if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
  				goto out_invalid_fh;
5df36e78d   Chuck Lever   NFS: Clean up nfs...
1774
  			mntfh->size = data->root.size;
764302ccb   Chuck Lever   NFS: Allow the "n...
1775
1776
  			args->version = 3;
  		} else {
5df36e78d   Chuck Lever   NFS: Clean up nfs...
1777
  			mntfh->size = NFS2_FHSIZE;
764302ccb   Chuck Lever   NFS: Allow the "n...
1778
1779
  			args->version = 2;
  		}
5df36e78d   Chuck Lever   NFS: Clean up nfs...
1780

5df36e78d   Chuck Lever   NFS: Clean up nfs...
1781
1782
1783
1784
1785
  
  		memcpy(mntfh->data, data->root.data, mntfh->size);
  		if (mntfh->size < sizeof(mntfh->data))
  			memset(mntfh->data + mntfh->size, 0,
  			       sizeof(mntfh->data) - mntfh->size);
6e88e0618   Chuck Lever   NFS: Verify serve...
1786

2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
1787
1788
1789
1790
  		/*
  		 * Translate to nfs_parsed_mount_data, which nfs_fill_super
  		 * can deal with.
  		 */
ff3525a53   Trond Myklebust   NFS: Don't apply ...
1791
  		args->flags		= data->flags & NFS_MOUNT_FLAGMASK;
d5eff1a34   Bryan Schumaker   NFS: Fix /proc/mo...
1792
  		args->flags		|= NFS_MOUNT_LEGACY_INTERFACE;
2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
1793
1794
  		args->rsize		= data->rsize;
  		args->wsize		= data->wsize;
2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
1795
1796
1797
1798
1799
1800
  		args->timeo		= data->timeo;
  		args->retrans		= data->retrans;
  		args->acregmin		= data->acregmin;
  		args->acregmax		= data->acregmax;
  		args->acdirmin		= data->acdirmin;
  		args->acdirmax		= data->acdirmax;
4c5680177   Chuck Lever   NFS: Support non-...
1801

4cfd74fc9   Chuck Lever   NFS: Mount option...
1802
  		memcpy(sap, &data->addr, sizeof(data->addr));
4c5680177   Chuck Lever   NFS: Support non-...
1803
  		args->nfs_server.addrlen = sizeof(data->addr);
4cfd74fc9   Chuck Lever   NFS: Mount option...
1804
  		if (!nfs_verify_server_address(sap))
4c5680177   Chuck Lever   NFS: Support non-...
1805
  			goto out_no_address;
2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
1806
  		if (!(data->flags & NFS_MOUNT_TCP))
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
1807
  			args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
1808
1809
1810
1811
  		/* N.B. caller will free nfs_server.hostname in all cases */
  		args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
  		args->namlen		= data->namlen;
  		args->bsize		= data->bsize;
dd07c9475   Chuck Lever   NFS: Set security...
1812
1813
1814
  
  		if (data->flags & NFS_MOUNT_SECFLAVOUR)
  			args->auth_flavors[0] = data->pseudoflavor;
63649bd70   Cyrill Gorcunov   NFS - fix potenti...
1815
1816
  		if (!args->nfs_server.hostname)
  			goto out_nomem;
f9c3a3802   Eric Paris   NFS: use new LSM ...
1817

5eebde232   Suresh Jayaraman   nfs: introduce mo...
1818
1819
1820
1821
1822
1823
  		if (!(data->flags & NFS_MOUNT_NONLM))
  			args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
  					 NFS_MOUNT_LOCAL_FCNTL);
  		else
  			args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
  					NFS_MOUNT_LOCAL_FCNTL);
f9c3a3802   Eric Paris   NFS: use new LSM ...
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
  		/*
  		 * The legacy version 6 binary mount data from userspace has a
  		 * field used only to transport selinux information into the
  		 * the kernel.  To continue to support that functionality we
  		 * have a touch of selinux knowledge here in the NFS code. The
  		 * userspace code converted context=blah to just blah so we are
  		 * converting back to the full string selinux understands.
  		 */
  		if (data->context[0]){
  #ifdef CONFIG_SECURITY_SELINUX
  			int rc;
  			char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL);
  			if (!opts_str)
  				return -ENOMEM;
  			strcpy(opts_str, "context=");
  			data->context[NFS_MAX_CONTEXT_LEN] = '\0';
  			strcat(opts_str, &data->context[0]);
  			rc = security_sb_parse_opts_str(opts_str, &args->lsm_opts);
  			kfree(opts_str);
  			if (rc)
  				return rc;
  #else
  			return -EINVAL;
  #endif
  		}
5df36e78d   Chuck Lever   NFS: Clean up nfs...
1849
  		break;
136d558ce   Chuck Lever   NFS: Add final pi...
1850
  	default: {
136d558ce   Chuck Lever   NFS: Add final pi...
1851
  		int status;
136d558ce   Chuck Lever   NFS: Add final pi...
1852

2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
1853
1854
  		if (nfs_parse_mount_options((char *)options, args) == 0)
  			return -EINVAL;
136d558ce   Chuck Lever   NFS: Add final pi...
1855

4cfd74fc9   Chuck Lever   NFS: Mount option...
1856
  		if (!nfs_verify_server_address(sap))
6e88e0618   Chuck Lever   NFS: Verify serve...
1857
  			goto out_no_address;
764302ccb   Chuck Lever   NFS: Allow the "n...
1858
1859
1860
1861
1862
1863
1864
  		if (args->version == 4)
  #ifdef CONFIG_NFS_V4
  			return nfs4_validate_text_mount_data(options,
  							     args, dev_name);
  #else
  			goto out_v4_not_compiled;
  #endif
f5855fecd   Trond Myklebust   NFS: Fix port and...
1865
  		nfs_set_port(sap, &args->nfs_server.port, 0);
ed596a8ad   Chuck Lever   NFS: Move the nfs...
1866

259875efe   Trond Myklebust   NFS: set transpor...
1867
  		nfs_set_mount_transport_protocol(args);
dc0458982   Chuck Lever   NFS: Use common d...
1868
1869
1870
1871
1872
1873
1874
  		status = nfs_parse_devname(dev_name,
  					   &args->nfs_server.hostname,
  					   PAGE_SIZE,
  					   &args->nfs_server.export_path,
  					   NFS_MAXPATHLEN);
  		if (!status)
  			status = nfs_try_mount(args, mntfh);
136d558ce   Chuck Lever   NFS: Add final pi...
1875

dc0458982   Chuck Lever   NFS: Use common d...
1876
1877
  		kfree(args->nfs_server.export_path);
  		args->nfs_server.export_path = NULL;
136d558ce   Chuck Lever   NFS: Add final pi...
1878

136d558ce   Chuck Lever   NFS: Add final pi...
1879
  		if (status)
fdc6e2c8c   Chuck Lever   NFS: Return a rea...
1880
  			return status;
136d558ce   Chuck Lever   NFS: Add final pi...
1881

136d558ce   Chuck Lever   NFS: Add final pi...
1882
1883
  		break;
  		}
f7b422b17   David Howells   NFS: Split fs/nfs...
1884
  	}
54ceac451   David Howells   NFS: Share NFS su...
1885
1886
  
  #ifndef CONFIG_NFS_V3
8a6e5deb8   Trond Myklebust   NFS: Get rid of t...
1887
  	if (args->version == 3)
5df36e78d   Chuck Lever   NFS: Clean up nfs...
1888
1889
  		goto out_v3_not_compiled;
  #endif /* !CONFIG_NFS_V3 */
f7b422b17   David Howells   NFS: Split fs/nfs...
1890

5df36e78d   Chuck Lever   NFS: Clean up nfs...
1891
  	return 0;
f7b422b17   David Howells   NFS: Split fs/nfs...
1892

5df36e78d   Chuck Lever   NFS: Clean up nfs...
1893
1894
1895
1896
  out_no_data:
  	dfprintk(MOUNT, "NFS: mount program didn't pass any mount data
  ");
  	return -EINVAL;
54ceac451   David Howells   NFS: Share NFS su...
1897

5df36e78d   Chuck Lever   NFS: Clean up nfs...
1898
1899
1900
1901
1902
  out_no_v3:
  	dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3
  ",
  		 data->version);
  	return -EINVAL;
f7b422b17   David Howells   NFS: Split fs/nfs...
1903

5df36e78d   Chuck Lever   NFS: Clean up nfs...
1904
1905
1906
1907
  out_no_sec:
  	dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS
  ");
  	return -EINVAL;
5df36e78d   Chuck Lever   NFS: Clean up nfs...
1908
1909
1910
1911
1912
1913
  #ifndef CONFIG_NFS_V3
  out_v3_not_compiled:
  	dfprintk(MOUNT, "NFS: NFSv3 is not compiled into kernel
  ");
  	return -EPROTONOSUPPORT;
  #endif /* !CONFIG_NFS_V3 */
764302ccb   Chuck Lever   NFS: Allow the "n...
1914
1915
1916
1917
1918
1919
  #ifndef CONFIG_NFS_V4
  out_v4_not_compiled:
  	dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel
  ");
  	return -EPROTONOSUPPORT;
  #endif /* !CONFIG_NFS_V4 */
63649bd70   Cyrill Gorcunov   NFS - fix potenti...
1920
1921
1922
1923
  out_nomem:
  	dfprintk(MOUNT, "NFS: not enough memory to handle mount options
  ");
  	return -ENOMEM;
5df36e78d   Chuck Lever   NFS: Clean up nfs...
1924
1925
1926
1927
1928
1929
1930
1931
1932
  out_no_address:
  	dfprintk(MOUNT, "NFS: mount program didn't pass remote address
  ");
  	return -EINVAL;
  
  out_invalid_fh:
  	dfprintk(MOUNT, "NFS: invalid root filehandle
  ");
  	return -EINVAL;
f7b422b17   David Howells   NFS: Split fs/nfs...
1933
  }
48b605f83   Jeff Layton   NFS: implement op...
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
  static int
  nfs_compare_remount_data(struct nfs_server *nfss,
  			 struct nfs_parsed_mount_data *data)
  {
  	if (data->flags != nfss->flags ||
  	    data->rsize != nfss->rsize ||
  	    data->wsize != nfss->wsize ||
  	    data->retrans != nfss->client->cl_timeout->to_retries ||
  	    data->auth_flavors[0] != nfss->client->cl_auth->au_flavor ||
  	    data->acregmin != nfss->acregmin / HZ ||
  	    data->acregmax != nfss->acregmax / HZ ||
  	    data->acdirmin != nfss->acdirmin / HZ ||
  	    data->acdirmax != nfss->acdirmax / HZ ||
  	    data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
bcd2ea17d   Trond Myklebust   NFS: Fix port ini...
1948
  	    data->nfs_server.port != nfss->port ||
48b605f83   Jeff Layton   NFS: implement op...
1949
  	    data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
a1be9eee2   Stefan Richter   NFS: suppress a b...
1950
1951
  	    !rpc_cmp_addr((struct sockaddr *)&data->nfs_server.address,
  			  (struct sockaddr *)&nfss->nfs_client->cl_addr))
48b605f83   Jeff Layton   NFS: implement op...
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
  		return -EINVAL;
  
  	return 0;
  }
  
  static int
  nfs_remount(struct super_block *sb, int *flags, char *raw_data)
  {
  	int error;
  	struct nfs_server *nfss = sb->s_fs_info;
  	struct nfs_parsed_mount_data *data;
  	struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data;
  	struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
cd1007256   Trond Myklebust   NFS: Fix a depend...
1965
  	u32 nfsvers = nfss->nfs_client->rpc_ops->version;
48b605f83   Jeff Layton   NFS: implement op...
1966
1967
1968
1969
1970
1971
1972
  
  	/*
  	 * Userspace mount programs that send binary options generally send
  	 * them populated with default values. We have no way to know which
  	 * ones were explicitly specified. Fall back to legacy behavior and
  	 * just return success.
  	 */
31c944699   Marc Zyngier   nfs_remount oops ...
1973
1974
1975
  	if ((nfsvers == 4 && (!options4 || options4->version == 1)) ||
  	    (nfsvers <= 3 && (!options || (options->version >= 1 &&
  					   options->version <= 6))))
48b605f83   Jeff Layton   NFS: implement op...
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
  		return 0;
  
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
  	if (data == NULL)
  		return -ENOMEM;
  
  	/* fill out struct with values from existing mount */
  	data->flags = nfss->flags;
  	data->rsize = nfss->rsize;
  	data->wsize = nfss->wsize;
  	data->retrans = nfss->client->cl_timeout->to_retries;
  	data->auth_flavors[0] = nfss->client->cl_auth->au_flavor;
  	data->acregmin = nfss->acregmin / HZ;
  	data->acregmax = nfss->acregmax / HZ;
  	data->acdirmin = nfss->acdirmin / HZ;
  	data->acdirmax = nfss->acdirmax / HZ;
  	data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
bcd2ea17d   Trond Myklebust   NFS: Fix port ini...
1993
  	data->nfs_server.port = nfss->port;
48b605f83   Jeff Layton   NFS: implement op...
1994
1995
1996
1997
1998
1999
2000
2001
  	data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
  	memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr,
  		data->nfs_server.addrlen);
  
  	/* overwrite those values with any that were specified */
  	error = nfs_parse_mount_options((char *)options, data);
  	if (error < 0)
  		goto out;
26c4c1707   Jeff Layton   nfs: don't lose M...
2002
2003
2004
2005
2006
2007
2008
2009
  	/*
  	 * noac is a special case. It implies -o sync, but that's not
  	 * necessarily reflected in the mtab options. do_remount_sb
  	 * will clear MS_SYNCHRONOUS if -o sync wasn't specified in the
  	 * remount options, so we have to explicitly reset it.
  	 */
  	if (data->flags & NFS_MOUNT_NOAC)
  		*flags |= MS_SYNCHRONOUS;
48b605f83   Jeff Layton   NFS: implement op...
2010
2011
2012
2013
2014
2015
  	/* compare new mount options with old ones */
  	error = nfs_compare_remount_data(nfss, data);
  out:
  	kfree(data);
  	return error;
  }
f7b422b17   David Howells   NFS: Split fs/nfs...
2016
  /*
54ceac451   David Howells   NFS: Share NFS su...
2017
   * Initialise the common bits of the superblock
f7b422b17   David Howells   NFS: Split fs/nfs...
2018
   */
54ceac451   David Howells   NFS: Share NFS su...
2019
  static inline void nfs_initialise_sb(struct super_block *sb)
f7b422b17   David Howells   NFS: Split fs/nfs...
2020
  {
54ceac451   David Howells   NFS: Share NFS su...
2021
  	struct nfs_server *server = NFS_SB(sb);
5006a76cc   David Howells   NFS: Eliminate cl...
2022

54ceac451   David Howells   NFS: Share NFS su...
2023
  	sb->s_magic = NFS_SUPER_MAGIC;
f7b422b17   David Howells   NFS: Split fs/nfs...
2024

54ceac451   David Howells   NFS: Share NFS su...
2025
2026
2027
  	/* We probably want something more informative here */
  	snprintf(sb->s_id, sizeof(sb->s_id),
  		 "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
5006a76cc   David Howells   NFS: Eliminate cl...
2028

54ceac451   David Howells   NFS: Share NFS su...
2029
2030
2031
  	if (sb->s_blocksize == 0)
  		sb->s_blocksize = nfs_block_bits(server->wsize,
  						 &sb->s_blocksize_bits);
f7b422b17   David Howells   NFS: Split fs/nfs...
2032

32a88aa1b   Jens Axboe   fs: Assign bdi in...
2033
  	sb->s_bdi = &server->backing_dev_info;
54ceac451   David Howells   NFS: Share NFS su...
2034
  	nfs_super_set_maxbytes(sb, server->maxfilesize);
f7b422b17   David Howells   NFS: Split fs/nfs...
2035
2036
2037
  }
  
  /*
54ceac451   David Howells   NFS: Share NFS su...
2038
   * Finish setting up an NFS2/3 superblock
f7b422b17   David Howells   NFS: Split fs/nfs...
2039
   */
2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
2040
2041
  static void nfs_fill_super(struct super_block *sb,
  			   struct nfs_parsed_mount_data *data)
f7b422b17   David Howells   NFS: Split fs/nfs...
2042
2043
  {
  	struct nfs_server *server = NFS_SB(sb);
5006a76cc   David Howells   NFS: Eliminate cl...
2044

54ceac451   David Howells   NFS: Share NFS su...
2045
2046
2047
2048
  	sb->s_blocksize_bits = 0;
  	sb->s_blocksize = 0;
  	if (data->bsize)
  		sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
f7b422b17   David Howells   NFS: Split fs/nfs...
2049

8a6e5deb8   Trond Myklebust   NFS: Get rid of t...
2050
  	if (server->nfs_client->rpc_ops->version == 3) {
54ceac451   David Howells   NFS: Share NFS su...
2051
2052
2053
2054
2055
  		/* The VFS shouldn't apply the umask to mode bits. We will do
  		 * so ourselves when necessary.
  		 */
  		sb->s_flags |= MS_POSIXACL;
  		sb->s_time_gran = 1;
816724e65   Trond Myklebust   Merge branch 'mas...
2056
  	}
54ceac451   David Howells   NFS: Share NFS su...
2057
2058
2059
  
  	sb->s_op = &nfs_sops;
   	nfs_initialise_sb(sb);
f7b422b17   David Howells   NFS: Split fs/nfs...
2060
2061
2062
  }
  
  /*
54ceac451   David Howells   NFS: Share NFS su...
2063
   * Finish setting up a cloned NFS2/3 superblock
f7b422b17   David Howells   NFS: Split fs/nfs...
2064
   */
54ceac451   David Howells   NFS: Share NFS su...
2065
2066
  static void nfs_clone_super(struct super_block *sb,
  			    const struct super_block *old_sb)
f7b422b17   David Howells   NFS: Split fs/nfs...
2067
  {
54ceac451   David Howells   NFS: Share NFS su...
2068
2069
2070
2071
2072
  	struct nfs_server *server = NFS_SB(sb);
  
  	sb->s_blocksize_bits = old_sb->s_blocksize_bits;
  	sb->s_blocksize = old_sb->s_blocksize;
  	sb->s_maxbytes = old_sb->s_maxbytes;
f7b422b17   David Howells   NFS: Split fs/nfs...
2073

8a6e5deb8   Trond Myklebust   NFS: Get rid of t...
2074
  	if (server->nfs_client->rpc_ops->version == 3) {
54ceac451   David Howells   NFS: Share NFS su...
2075
2076
  		/* The VFS shouldn't apply the umask to mode bits. We will do
  		 * so ourselves when necessary.
f7b422b17   David Howells   NFS: Split fs/nfs...
2077
2078
  		 */
  		sb->s_flags |= MS_POSIXACL;
f7b422b17   David Howells   NFS: Split fs/nfs...
2079
  		sb->s_time_gran = 1;
f7b422b17   David Howells   NFS: Split fs/nfs...
2080
  	}
54ceac451   David Howells   NFS: Share NFS su...
2081
2082
  	sb->s_op = old_sb->s_op;
   	nfs_initialise_sb(sb);
f7b422b17   David Howells   NFS: Split fs/nfs...
2083
  }
275a5d24b   Trond Myklebust   NFS: Error when m...
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
  static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
  {
  	const struct nfs_server *a = s->s_fs_info;
  	const struct rpc_clnt *clnt_a = a->client;
  	const struct rpc_clnt *clnt_b = b->client;
  
  	if ((s->s_flags & NFS_MS_MASK) != (flags & NFS_MS_MASK))
  		goto Ebusy;
  	if (a->nfs_client != b->nfs_client)
  		goto Ebusy;
  	if (a->flags != b->flags)
  		goto Ebusy;
  	if (a->wsize != b->wsize)
  		goto Ebusy;
  	if (a->rsize != b->rsize)
  		goto Ebusy;
  	if (a->acregmin != b->acregmin)
  		goto Ebusy;
  	if (a->acregmax != b->acregmax)
  		goto Ebusy;
  	if (a->acdirmin != b->acdirmin)
  		goto Ebusy;
  	if (a->acdirmax != b->acdirmax)
  		goto Ebusy;
  	if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
  		goto Ebusy;
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2110
  	return 1;
275a5d24b   Trond Myklebust   NFS: Error when m...
2111
  Ebusy:
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
  	return 0;
  }
  
  struct nfs_sb_mountdata {
  	struct nfs_server *server;
  	int mntflags;
  };
  
  static int nfs_set_super(struct super_block *s, void *data)
  {
  	struct nfs_sb_mountdata *sb_mntdata = data;
  	struct nfs_server *server = sb_mntdata->server;
  	int ret;
  
  	s->s_flags = sb_mntdata->mntflags;
  	s->s_fs_info = server;
8b244ff2f   Al Viro   switch nfs to ->s...
2128
  	s->s_d_op = server->nfs_client->rpc_ops->dentry_ops;
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2129
2130
2131
2132
2133
  	ret = set_anon_super(s, server);
  	if (ret == 0)
  		server->s_dev = s->s_dev;
  	return ret;
  }
fd00a8ff8   Chuck Lever   NFS: Add support ...
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
  static int nfs_compare_super_address(struct nfs_server *server1,
  				     struct nfs_server *server2)
  {
  	struct sockaddr *sap1, *sap2;
  
  	sap1 = (struct sockaddr *)&server1->nfs_client->cl_addr;
  	sap2 = (struct sockaddr *)&server2->nfs_client->cl_addr;
  
  	if (sap1->sa_family != sap2->sa_family)
  		return 0;
  
  	switch (sap1->sa_family) {
  	case AF_INET: {
  		struct sockaddr_in *sin1 = (struct sockaddr_in *)sap1;
  		struct sockaddr_in *sin2 = (struct sockaddr_in *)sap2;
  		if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr)
  			return 0;
  		if (sin1->sin_port != sin2->sin_port)
  			return 0;
  		break;
  	}
  	case AF_INET6: {
  		struct sockaddr_in6 *sin1 = (struct sockaddr_in6 *)sap1;
  		struct sockaddr_in6 *sin2 = (struct sockaddr_in6 *)sap2;
  		if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
  			return 0;
  		if (sin1->sin6_port != sin2->sin6_port)
  			return 0;
  		break;
  	}
  	default:
  		return 0;
  	}
  
  	return 1;
  }
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2170
2171
2172
2173
2174
  static int nfs_compare_super(struct super_block *sb, void *data)
  {
  	struct nfs_sb_mountdata *sb_mntdata = data;
  	struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb);
  	int mntflags = sb_mntdata->mntflags;
fd00a8ff8   Chuck Lever   NFS: Add support ...
2175
  	if (!nfs_compare_super_address(old, server))
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2176
2177
2178
2179
2180
2181
2182
  		return 0;
  	/* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
  	if (old->flags & NFS_MOUNT_UNSHARED)
  		return 0;
  	if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
  		return 0;
  	return nfs_compare_mount_options(sb, server, mntflags);
275a5d24b   Trond Myklebust   NFS: Error when m...
2183
  }
fa799759f   Miklos Szeredi   mm: bdi: expose t...
2184
2185
2186
2187
  static int nfs_bdi_register(struct nfs_server *server)
  {
  	return bdi_register_dev(&server->backing_dev_info, server->s_dev);
  }
011949811   Al Viro   nfs: switch NFS f...
2188
2189
  static struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *raw_data)
f7b422b17   David Howells   NFS: Split fs/nfs...
2190
  {
f7b422b17   David Howells   NFS: Split fs/nfs...
2191
2192
  	struct nfs_server *server = NULL;
  	struct super_block *s;
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2193
2194
  	struct nfs_parsed_mount_data *data;
  	struct nfs_fh *mntfh;
011949811   Al Viro   nfs: switch NFS f...
2195
  	struct dentry *mntroot = ERR_PTR(-ENOMEM);
75180df2e   Trond Myklebust   NFS: Add the moun...
2196
  	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2197
2198
2199
  	struct nfs_sb_mountdata sb_mntdata = {
  		.mntflags = flags,
  	};
011949811   Al Viro   nfs: switch NFS f...
2200
  	int error;
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2201

1e657bd51   Paulius Zaleckas   Regression: fix m...
2202
  	data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION);
b157b06ca   Trond Myklebust   NFS: Cleanup file...
2203
  	mntfh = nfs_alloc_fhandle();
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2204
  	if (data == NULL || mntfh == NULL)
8a0d551a5   Jeff Layton   nfs: fix regressi...
2205
  		goto out;
f9c3a3802   Eric Paris   NFS: use new LSM ...
2206

54ceac451   David Howells   NFS: Share NFS su...
2207
  	/* Validate the mount data */
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2208
  	error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name);
011949811   Al Viro   nfs: switch NFS f...
2209
2210
  	if (error < 0) {
  		mntroot = ERR_PTR(error);
0655960f7   Chuck Lever   NFS: Clean up err...
2211
  		goto out;
011949811   Al Viro   nfs: switch NFS f...
2212
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2213

764302ccb   Chuck Lever   NFS: Allow the "n...
2214
2215
  #ifdef CONFIG_NFS_V4
  	if (data->version == 4) {
011949811   Al Viro   nfs: switch NFS f...
2216
  		mntroot = nfs4_try_mount(flags, dev_name, data);
764302ccb   Chuck Lever   NFS: Allow the "n...
2217
2218
2219
  		goto out;
  	}
  #endif	/* CONFIG_NFS_V4 */
54ceac451   David Howells   NFS: Share NFS su...
2220
  	/* Get a volume representation */
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2221
  	server = nfs_create_server(data, mntfh);
54ceac451   David Howells   NFS: Share NFS su...
2222
  	if (IS_ERR(server)) {
011949811   Al Viro   nfs: switch NFS f...
2223
  		mntroot = ERR_CAST(server);
0655960f7   Chuck Lever   NFS: Clean up err...
2224
  		goto out;
f7b422b17   David Howells   NFS: Split fs/nfs...
2225
  	}
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2226
  	sb_mntdata.server = server;
f7b422b17   David Howells   NFS: Split fs/nfs...
2227

75180df2e   Trond Myklebust   NFS: Add the moun...
2228
2229
  	if (server->flags & NFS_MOUNT_UNSHARED)
  		compare_super = NULL;
fb2088ccc   Sachin Prabhu   nfs: Do not allow...
2230
2231
2232
  	/* -o noac implies -o sync */
  	if (server->flags & NFS_MOUNT_NOAC)
  		sb_mntdata.mntflags |= MS_SYNCHRONOUS;
54ceac451   David Howells   NFS: Share NFS su...
2233
  	/* Get a superblock - note that we may end up sharing one that already exists */
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2234
  	s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
816724e65   Trond Myklebust   Merge branch 'mas...
2235
  	if (IS_ERR(s)) {
011949811   Al Viro   nfs: switch NFS f...
2236
  		mntroot = ERR_CAST(s);
54ceac451   David Howells   NFS: Share NFS su...
2237
  		goto out_err_nosb;
816724e65   Trond Myklebust   Merge branch 'mas...
2238
  	}
54ceac451   David Howells   NFS: Share NFS su...
2239
2240
2241
  	if (s->s_fs_info != server) {
  		nfs_free_server(server);
  		server = NULL;
fa799759f   Miklos Szeredi   mm: bdi: expose t...
2242
2243
  	} else {
  		error = nfs_bdi_register(server);
011949811   Al Viro   nfs: switch NFS f...
2244
2245
  		if (error) {
  			mntroot = ERR_PTR(error);
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2246
  			goto error_splat_bdi;
011949811   Al Viro   nfs: switch NFS f...
2247
  		}
54ceac451   David Howells   NFS: Share NFS su...
2248
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2249

54ceac451   David Howells   NFS: Share NFS su...
2250
2251
  	if (!s->s_root) {
  		/* initial superblock/root creation */
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2252
  		nfs_fill_super(s, data);
160bc1604   Jesper Juhl   NFS: Remove dead ...
2253
  		nfs_fscache_get_super_cookie(s, data->fscache_uniq, NULL);
54ceac451   David Howells   NFS: Share NFS su...
2254
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2255

0d5839ad0   Al Viro   nfs: propagate de...
2256
  	mntroot = nfs_get_root(s, mntfh, dev_name);
011949811   Al Viro   nfs: switch NFS f...
2257
  	if (IS_ERR(mntroot))
54ceac451   David Howells   NFS: Share NFS su...
2258
  		goto error_splat_super;
816724e65   Trond Myklebust   Merge branch 'mas...
2259

33852a1f2   Trond Myklebust   NFS: Reduce the N...
2260
  	error = security_sb_set_mnt_opts(s, &data->lsm_opts);
f9c3a3802   Eric Paris   NFS: use new LSM ...
2261
2262
  	if (error)
  		goto error_splat_root;
54ceac451   David Howells   NFS: Share NFS su...
2263
  	s->s_flags |= MS_ACTIVE;
0655960f7   Chuck Lever   NFS: Clean up err...
2264
2265
  
  out:
8a0d551a5   Jeff Layton   nfs: fix regressi...
2266
  	nfs_free_parsed_mount_data(data);
b157b06ca   Trond Myklebust   NFS: Cleanup file...
2267
  	nfs_free_fhandle(mntfh);
011949811   Al Viro   nfs: switch NFS f...
2268
  	return mntroot;
816724e65   Trond Myklebust   Merge branch 'mas...
2269

54ceac451   David Howells   NFS: Share NFS su...
2270
2271
  out_err_nosb:
  	nfs_free_server(server);
0655960f7   Chuck Lever   NFS: Clean up err...
2272
  	goto out;
54ceac451   David Howells   NFS: Share NFS su...
2273

f9c3a3802   Eric Paris   NFS: use new LSM ...
2274
2275
  error_splat_root:
  	dput(mntroot);
011949811   Al Viro   nfs: switch NFS f...
2276
  	mntroot = ERR_PTR(error);
54ceac451   David Howells   NFS: Share NFS su...
2277
  error_splat_super:
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2278
2279
2280
  	if (server && !s->s_root)
  		bdi_unregister(&server->backing_dev_info);
  error_splat_bdi:
6f5bbff9a   Al Viro   Convert obvious p...
2281
  	deactivate_locked_super(s);
0655960f7   Chuck Lever   NFS: Clean up err...
2282
  	goto out;
f7b422b17   David Howells   NFS: Split fs/nfs...
2283
  }
54ceac451   David Howells   NFS: Share NFS su...
2284
  /*
387c149b5   Trond Myklebust   NFS: Fix a umount...
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
   * Ensure that we unregister the bdi before kill_anon_super
   * releases the device name
   */
  static void nfs_put_super(struct super_block *s)
  {
  	struct nfs_server *server = NFS_SB(s);
  
  	bdi_unregister(&server->backing_dev_info);
  }
  
  /*
54ceac451   David Howells   NFS: Share NFS su...
2296
2297
   * Destroy an NFS2/3 superblock
   */
f7b422b17   David Howells   NFS: Split fs/nfs...
2298
2299
2300
2301
2302
  static void nfs_kill_super(struct super_block *s)
  {
  	struct nfs_server *server = NFS_SB(s);
  
  	kill_anon_super(s);
08734048b   David Howells   NFS: Define and c...
2303
  	nfs_fscache_release_super_cookie(s);
54ceac451   David Howells   NFS: Share NFS su...
2304
  	nfs_free_server(server);
f7b422b17   David Howells   NFS: Split fs/nfs...
2305
  }
54ceac451   David Howells   NFS: Share NFS su...
2306
2307
2308
  /*
   * Clone an NFS2/3 server record on xdev traversal (FSID-change)
   */
31f43471e   Al Viro   convert simple ca...
2309
2310
2311
  static struct dentry *
  nfs_xdev_mount(struct file_system_type *fs_type, int flags,
  		const char *dev_name, void *raw_data)
f7b422b17   David Howells   NFS: Split fs/nfs...
2312
2313
  {
  	struct nfs_clone_mount *data = raw_data;
54ceac451   David Howells   NFS: Share NFS su...
2314
2315
2316
  	struct super_block *s;
  	struct nfs_server *server;
  	struct dentry *mntroot;
75180df2e   Trond Myklebust   NFS: Add the moun...
2317
  	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2318
2319
2320
  	struct nfs_sb_mountdata sb_mntdata = {
  		.mntflags = flags,
  	};
54ceac451   David Howells   NFS: Share NFS su...
2321
  	int error;
f7b422b17   David Howells   NFS: Split fs/nfs...
2322

31f43471e   Al Viro   convert simple ca...
2323
2324
  	dprintk("--> nfs_xdev_mount()
  ");
f7b422b17   David Howells   NFS: Split fs/nfs...
2325

54ceac451   David Howells   NFS: Share NFS su...
2326
2327
2328
2329
2330
2331
  	/* create a new volume representation */
  	server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
  	if (IS_ERR(server)) {
  		error = PTR_ERR(server);
  		goto out_err_noserver;
  	}
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2332
  	sb_mntdata.server = server;
8fa5c000d   David Howells   NFS: Move rpc_ops...
2333

75180df2e   Trond Myklebust   NFS: Add the moun...
2334
2335
  	if (server->flags & NFS_MOUNT_UNSHARED)
  		compare_super = NULL;
fb2088ccc   Sachin Prabhu   nfs: Do not allow...
2336
2337
2338
  	/* -o noac implies -o sync */
  	if (server->flags & NFS_MOUNT_NOAC)
  		sb_mntdata.mntflags |= MS_SYNCHRONOUS;
54ceac451   David Howells   NFS: Share NFS su...
2339
  	/* Get a superblock - note that we may end up sharing one that already exists */
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2340
  	s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
54ceac451   David Howells   NFS: Share NFS su...
2341
2342
2343
2344
  	if (IS_ERR(s)) {
  		error = PTR_ERR(s);
  		goto out_err_nosb;
  	}
5006a76cc   David Howells   NFS: Eliminate cl...
2345

54ceac451   David Howells   NFS: Share NFS su...
2346
2347
2348
  	if (s->s_fs_info != server) {
  		nfs_free_server(server);
  		server = NULL;
fa799759f   Miklos Szeredi   mm: bdi: expose t...
2349
2350
2351
  	} else {
  		error = nfs_bdi_register(server);
  		if (error)
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2352
  			goto error_splat_bdi;
f7b422b17   David Howells   NFS: Split fs/nfs...
2353
  	}
24c8dbbb5   David Howells   NFS: Generalise t...
2354

54ceac451   David Howells   NFS: Share NFS su...
2355
2356
  	if (!s->s_root) {
  		/* initial superblock/root creation */
54ceac451   David Howells   NFS: Share NFS su...
2357
  		nfs_clone_super(s, data->sb);
2df548063   David Howells   NFS: Propagate 'f...
2358
  		nfs_fscache_get_super_cookie(s, NULL, data);
54ceac451   David Howells   NFS: Share NFS su...
2359
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2360

0d5839ad0   Al Viro   nfs: propagate de...
2361
  	mntroot = nfs_get_root(s, data->fh, dev_name);
54ceac451   David Howells   NFS: Share NFS su...
2362
2363
2364
  	if (IS_ERR(mntroot)) {
  		error = PTR_ERR(mntroot);
  		goto error_splat_super;
f7b422b17   David Howells   NFS: Split fs/nfs...
2365
  	}
e9cc6c234   Trond Myklebust   NFS: Fix a possib...
2366
  	if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
4c1fe2f78   Neil Brown   kernel BUG at fs/...
2367
2368
2369
2370
  		dput(mntroot);
  		error = -ESTALE;
  		goto error_splat_super;
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2371

54ceac451   David Howells   NFS: Share NFS su...
2372
  	s->s_flags |= MS_ACTIVE;
f7b422b17   David Howells   NFS: Split fs/nfs...
2373

f9c3a3802   Eric Paris   NFS: use new LSM ...
2374
2375
  	/* clone any lsm security options from the parent to the new sb */
  	security_sb_clone_mnt_opts(data->sb, s);
31f43471e   Al Viro   convert simple ca...
2376
2377
2378
  	dprintk("<-- nfs_xdev_mount() = 0
  ");
  	return mntroot;
24c8dbbb5   David Howells   NFS: Generalise t...
2379

54ceac451   David Howells   NFS: Share NFS su...
2380
2381
2382
  out_err_nosb:
  	nfs_free_server(server);
  out_err_noserver:
31f43471e   Al Viro   convert simple ca...
2383
2384
2385
  	dprintk("<-- nfs_xdev_mount() = %d [error]
  ", error);
  	return ERR_PTR(error);
f7b422b17   David Howells   NFS: Split fs/nfs...
2386

54ceac451   David Howells   NFS: Share NFS su...
2387
  error_splat_super:
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2388
2389
2390
  	if (server && !s->s_root)
  		bdi_unregister(&server->backing_dev_info);
  error_splat_bdi:
6f5bbff9a   Al Viro   Convert obvious p...
2391
  	deactivate_locked_super(s);
31f43471e   Al Viro   convert simple ca...
2392
2393
2394
  	dprintk("<-- nfs_xdev_mount() = %d [splat]
  ", error);
  	return ERR_PTR(error);
f7b422b17   David Howells   NFS: Split fs/nfs...
2395
  }
54ceac451   David Howells   NFS: Share NFS su...
2396
  #ifdef CONFIG_NFS_V4
f7b422b17   David Howells   NFS: Split fs/nfs...
2397
  /*
54ceac451   David Howells   NFS: Share NFS su...
2398
   * Finish setting up a cloned NFS4 superblock
f7b422b17   David Howells   NFS: Split fs/nfs...
2399
   */
54ceac451   David Howells   NFS: Share NFS su...
2400
2401
  static void nfs4_clone_super(struct super_block *sb,
  			    const struct super_block *old_sb)
f7b422b17   David Howells   NFS: Split fs/nfs...
2402
  {
54ceac451   David Howells   NFS: Share NFS su...
2403
2404
2405
  	sb->s_blocksize_bits = old_sb->s_blocksize_bits;
  	sb->s_blocksize = old_sb->s_blocksize;
  	sb->s_maxbytes = old_sb->s_maxbytes;
f7b422b17   David Howells   NFS: Split fs/nfs...
2406
  	sb->s_time_gran = 1;
54ceac451   David Howells   NFS: Share NFS su...
2407
  	sb->s_op = old_sb->s_op;
a8a5da996   Aneesh Kumar K.V   nfs: Set MS_POSIX...
2408
2409
2410
2411
2412
  	/*
  	 * The VFS shouldn't apply the umask to mode bits. We will do
  	 * so ourselves when necessary.
  	 */
  	sb->s_flags  |= MS_POSIXACL;
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
2413
2414
  	sb->s_xattr  = old_sb->s_xattr;
  	nfs_initialise_sb(sb);
f7b422b17   David Howells   NFS: Split fs/nfs...
2415
  }
54ceac451   David Howells   NFS: Share NFS su...
2416
2417
2418
2419
  /*
   * Set up an NFS4 superblock
   */
  static void nfs4_fill_super(struct super_block *sb)
f7b422b17   David Howells   NFS: Split fs/nfs...
2420
  {
54ceac451   David Howells   NFS: Share NFS su...
2421
2422
  	sb->s_time_gran = 1;
  	sb->s_op = &nfs4_sops;
a8a5da996   Aneesh Kumar K.V   nfs: Set MS_POSIX...
2423
2424
2425
2426
2427
  	/*
  	 * The VFS shouldn't apply the umask to mode bits. We will do
  	 * so ourselves when necessary.
  	 */
  	sb->s_flags  |= MS_POSIXACL;
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
2428
  	sb->s_xattr = nfs4_xattr_handlers;
54ceac451   David Howells   NFS: Share NFS su...
2429
  	nfs_initialise_sb(sb);
f7b422b17   David Howells   NFS: Split fs/nfs...
2430
  }
01c3f0522   Trond Myklebust   NFSv4: Fix the 'n...
2431
2432
  static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
  {
5eebde232   Suresh Jayaraman   nfs: introduce mo...
2433
2434
  	args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
  			 NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
01c3f0522   Trond Myklebust   NFSv4: Fix the 'n...
2435
  }
7630c852e   Chuck Lever   NFS: Refactor NFS...
2436
2437
2438
2439
2440
  static int nfs4_validate_text_mount_data(void *options,
  					 struct nfs_parsed_mount_data *args,
  					 const char *dev_name)
  {
  	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
f5855fecd   Trond Myklebust   NFS: Fix port and...
2441
  	nfs_set_port(sap, &args->nfs_server.port, NFS_PORT);
7630c852e   Chuck Lever   NFS: Refactor NFS...
2442
2443
2444
2445
  
  	nfs_validate_transport_protocol(args);
  
  	nfs4_validate_mount_flags(args);
2ecda72b4   Trond Myklebust   NFSv4: Disallow '...
2446
2447
2448
2449
2450
2451
  	if (args->version != 4) {
  		dfprintk(MOUNT,
  			 "NFS4: Illegal mount version
  ");
  		return -EINVAL;
  	}
7630c852e   Chuck Lever   NFS: Refactor NFS...
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
  	if (args->auth_flavor_len > 1) {
  		dfprintk(MOUNT,
  			 "NFS4: Too many RPC auth flavours specified
  ");
  		return -EINVAL;
  	}
  
  	if (args->client_address == NULL) {
  		dfprintk(MOUNT,
  			 "NFS4: mount program didn't pass callback address
  ");
  		return -EINVAL;
  	}
  
  	return nfs_parse_devname(dev_name,
  				   &args->nfs_server.hostname,
  				   NFS4_MAXNAMLEN,
  				   &args->nfs_server.export_path,
  				   NFS4_MAXPATHLEN);
  }
54ceac451   David Howells   NFS: Share NFS su...
2472
  /*
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2473
2474
   * Validate NFSv4 mount options
   */
91ea40b9c   \"Talpey, Thomas\   NFS: use in-kerne...
2475
2476
2477
  static int nfs4_validate_mount_data(void *options,
  				    struct nfs_parsed_mount_data *args,
  				    const char *dev_name)
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2478
  {
4cfd74fc9   Chuck Lever   NFS: Mount option...
2479
  	struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
91ea40b9c   \"Talpey, Thomas\   NFS: use in-kerne...
2480
  	struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2481
2482
2483
2484
2485
2486
2487
  	char *c;
  
  	if (data == NULL)
  		goto out_no_data;
  
  	switch (data->version) {
  	case 1:
4c5680177   Chuck Lever   NFS: Support non-...
2488
2489
2490
  		if (data->host_addrlen > sizeof(args->nfs_server.address))
  			goto out_no_address;
  		if (data->host_addrlen == 0)
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2491
  			goto out_no_address;
4c5680177   Chuck Lever   NFS: Support non-...
2492
  		args->nfs_server.addrlen = data->host_addrlen;
4cfd74fc9   Chuck Lever   NFS: Mount option...
2493
  		if (copy_from_user(sap, data->host_addr, data->host_addrlen))
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2494
  			return -EFAULT;
4cfd74fc9   Chuck Lever   NFS: Mount option...
2495
  		if (!nfs_verify_server_address(sap))
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2496
  			goto out_no_address;
6738b2512   Chuck Lever   NFS4: Set securit...
2497
2498
2499
  		if (data->auth_flavourlen) {
  			if (data->auth_flavourlen > 1)
  				goto out_inval_auth;
20c71f5e0   Trond Myklebust   NFSv4: Fix a bug ...
2500
  			if (copy_from_user(&args->auth_flavors[0],
91ea40b9c   \"Talpey, Thomas\   NFS: use in-kerne...
2501
  					   data->auth_flavours,
20c71f5e0   Trond Myklebust   NFSv4: Fix a bug ...
2502
  					   sizeof(args->auth_flavors[0])))
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2503
  				return -EFAULT;
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2504
2505
2506
2507
2508
  		}
  
  		c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
  		if (IS_ERR(c))
  			return PTR_ERR(c);
91ea40b9c   \"Talpey, Thomas\   NFS: use in-kerne...
2509
  		args->nfs_server.hostname = c;
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2510
2511
2512
2513
  
  		c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
  		if (IS_ERR(c))
  			return PTR_ERR(c);
91ea40b9c   \"Talpey, Thomas\   NFS: use in-kerne...
2514
2515
2516
  		args->nfs_server.export_path = c;
  		dfprintk(MOUNT, "NFS: MNTPATH: '%s'
  ", c);
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2517
2518
2519
2520
  
  		c = strndup_user(data->client_addr.data, 16);
  		if (IS_ERR(c))
  			return PTR_ERR(c);
91ea40b9c   \"Talpey, Thomas\   NFS: use in-kerne...
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
  		args->client_address = c;
  
  		/*
  		 * Translate to nfs_parsed_mount_data, which nfs4_fill_super
  		 * can deal with.
  		 */
  
  		args->flags	= data->flags & NFS4_MOUNT_FLAGMASK;
  		args->rsize	= data->rsize;
  		args->wsize	= data->wsize;
  		args->timeo	= data->timeo;
  		args->retrans	= data->retrans;
  		args->acregmin	= data->acregmin;
  		args->acregmax	= data->acregmax;
  		args->acdirmin	= data->acdirmin;
  		args->acdirmax	= data->acdirmax;
  		args->nfs_server.protocol = data->proto;
259875efe   Trond Myklebust   NFS: set transpor...
2538
  		nfs_validate_transport_protocol(args);
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2539
2540
  
  		break;
7630c852e   Chuck Lever   NFS: Refactor NFS...
2541
  	default:
91ea40b9c   \"Talpey, Thomas\   NFS: use in-kerne...
2542
  		if (nfs_parse_mount_options((char *)options, args) == 0)
800712252   Chuck Lever   NFS: Add support ...
2543
  			return -EINVAL;
4cfd74fc9   Chuck Lever   NFS: Mount option...
2544
  		if (!nfs_verify_server_address(sap))
800712252   Chuck Lever   NFS: Add support ...
2545
  			return -EINVAL;
dc0458982   Chuck Lever   NFS: Use common d...
2546

7630c852e   Chuck Lever   NFS: Refactor NFS...
2547
  		return nfs4_validate_text_mount_data(options, args, dev_name);
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
  	}
  
  	return 0;
  
  out_no_data:
  	dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data
  ");
  	return -EINVAL;
  
  out_inval_auth:
  	dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d
  ",
  		 data->auth_flavourlen);
  	return -EINVAL;
  
  out_no_address:
  	dfprintk(MOUNT, "NFS4: mount program didn't pass remote address
  ");
  	return -EINVAL;
f0768ebd0   Chuck Lever   NFS: Introduce nf...
2567
2568
2569
  }
  
  /*
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2570
   * Get the superblock for the NFS4 root partition
54ceac451   David Howells   NFS: Share NFS su...
2571
   */
31f43471e   Al Viro   convert simple ca...
2572
2573
2574
  static struct dentry *
  nfs4_remote_mount(struct file_system_type *fs_type, int flags,
  		  const char *dev_name, void *raw_data)
f7b422b17   David Howells   NFS: Split fs/nfs...
2575
  {
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2576
  	struct nfs_parsed_mount_data *data = raw_data;
54ceac451   David Howells   NFS: Share NFS su...
2577
2578
  	struct super_block *s;
  	struct nfs_server *server;
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2579
  	struct nfs_fh *mntfh;
54ceac451   David Howells   NFS: Share NFS su...
2580
  	struct dentry *mntroot;
75180df2e   Trond Myklebust   NFS: Add the moun...
2581
  	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2582
2583
2584
  	struct nfs_sb_mountdata sb_mntdata = {
  		.mntflags = flags,
  	};
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2585
  	int error = -ENOMEM;
b157b06ca   Trond Myklebust   NFS: Cleanup file...
2586
  	mntfh = nfs_alloc_fhandle();
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2587
  	if (data == NULL || mntfh == NULL)
8a0d551a5   Jeff Layton   nfs: fix regressi...
2588
  		goto out;
f9c3a3802   Eric Paris   NFS: use new LSM ...
2589

54ceac451   David Howells   NFS: Share NFS su...
2590
  	/* Get a volume representation */
33852a1f2   Trond Myklebust   NFS: Reduce the N...
2591
  	server = nfs4_create_server(data, mntfh);
54ceac451   David Howells   NFS: Share NFS su...
2592
2593
  	if (IS_ERR(server)) {
  		error = PTR_ERR(server);
29eb981a3   Chuck Lever   NFS: Clean-up: Re...
2594
  		goto out;
f7b422b17   David Howells   NFS: Split fs/nfs...
2595
  	}
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2596
  	sb_mntdata.server = server;
f7b422b17   David Howells   NFS: Split fs/nfs...
2597

75180df2e   Trond Myklebust   NFS: Add the moun...
2598
2599
  	if (server->flags & NFS4_MOUNT_UNSHARED)
  		compare_super = NULL;
fb2088ccc   Sachin Prabhu   nfs: Do not allow...
2600
2601
2602
  	/* -o noac implies -o sync */
  	if (server->flags & NFS_MOUNT_NOAC)
  		sb_mntdata.mntflags |= MS_SYNCHRONOUS;
54ceac451   David Howells   NFS: Share NFS su...
2603
  	/* Get a superblock - note that we may end up sharing one that already exists */
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2604
  	s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
816724e65   Trond Myklebust   Merge branch 'mas...
2605
2606
  	if (IS_ERR(s)) {
  		error = PTR_ERR(s);
f7b422b17   David Howells   NFS: Split fs/nfs...
2607
  		goto out_free;
816724e65   Trond Myklebust   Merge branch 'mas...
2608
  	}
5dd3177ae   Trond Myklebust   NFSv4: Fix a use-...
2609
2610
2611
  	if (s->s_fs_info != server) {
  		nfs_free_server(server);
  		server = NULL;
fa799759f   Miklos Szeredi   mm: bdi: expose t...
2612
2613
2614
  	} else {
  		error = nfs_bdi_register(server);
  		if (error)
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2615
  			goto error_splat_bdi;
5dd3177ae   Trond Myklebust   NFSv4: Fix a use-...
2616
  	}
54ceac451   David Howells   NFS: Share NFS su...
2617
2618
  	if (!s->s_root) {
  		/* initial superblock/root creation */
54ceac451   David Howells   NFS: Share NFS su...
2619
  		nfs4_fill_super(s);
2df548063   David Howells   NFS: Propagate 'f...
2620
2621
  		nfs_fscache_get_super_cookie(
  			s, data ? data->fscache_uniq : NULL, NULL);
54ceac451   David Howells   NFS: Share NFS su...
2622
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2623

0d5839ad0   Al Viro   nfs: propagate de...
2624
  	mntroot = nfs4_get_root(s, mntfh, dev_name);
54ceac451   David Howells   NFS: Share NFS su...
2625
2626
2627
  	if (IS_ERR(mntroot)) {
  		error = PTR_ERR(mntroot);
  		goto error_splat_super;
f7b422b17   David Howells   NFS: Split fs/nfs...
2628
  	}
54ceac451   David Howells   NFS: Share NFS su...
2629

33852a1f2   Trond Myklebust   NFS: Reduce the N...
2630
  	error = security_sb_set_mnt_opts(s, &data->lsm_opts);
46c8ac742   Eric Paris   nfs/lsm: make NFS...
2631
2632
  	if (error)
  		goto error_splat_root;
f7b422b17   David Howells   NFS: Split fs/nfs...
2633
  	s->s_flags |= MS_ACTIVE;
31f43471e   Al Viro   convert simple ca...
2634

31f43471e   Al Viro   convert simple ca...
2635
2636
  	nfs_free_fhandle(mntfh);
  	return mntroot;
29eb981a3   Chuck Lever   NFS: Clean-up: Re...
2637
2638
  
  out:
b157b06ca   Trond Myklebust   NFS: Cleanup file...
2639
  	nfs_free_fhandle(mntfh);
31f43471e   Al Viro   convert simple ca...
2640
  	return ERR_PTR(error);
54ceac451   David Howells   NFS: Share NFS su...
2641

f7b422b17   David Howells   NFS: Split fs/nfs...
2642
  out_free:
54ceac451   David Howells   NFS: Share NFS su...
2643
  	nfs_free_server(server);
29eb981a3   Chuck Lever   NFS: Clean-up: Re...
2644
  	goto out;
54ceac451   David Howells   NFS: Share NFS su...
2645

46c8ac742   Eric Paris   nfs/lsm: make NFS...
2646
2647
  error_splat_root:
  	dput(mntroot);
54ceac451   David Howells   NFS: Share NFS su...
2648
  error_splat_super:
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2649
2650
2651
  	if (server && !s->s_root)
  		bdi_unregister(&server->backing_dev_info);
  error_splat_bdi:
6f5bbff9a   Al Viro   Convert obvious p...
2652
  	deactivate_locked_super(s);
29eb981a3   Chuck Lever   NFS: Clean-up: Re...
2653
  	goto out;
f7b422b17   David Howells   NFS: Split fs/nfs...
2654
  }
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
  static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
  		int flags, void *data, const char *hostname)
  {
  	struct vfsmount *root_mnt;
  	char *root_devname;
  	size_t len;
  
  	len = strlen(hostname) + 3;
  	root_devname = kmalloc(len, GFP_KERNEL);
  	if (root_devname == NULL)
  		return ERR_PTR(-ENOMEM);
  	snprintf(root_devname, len, "%s:/", hostname);
  	root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
  	kfree(root_devname);
  	return root_mnt;
  }
ce587e07b   Trond Myklebust   NFS: Prevent the ...
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
  struct nfs_referral_count {
  	struct list_head list;
  	const struct task_struct *task;
  	unsigned int referral_count;
  };
  
  static LIST_HEAD(nfs_referral_count_list);
  static DEFINE_SPINLOCK(nfs_referral_count_list_lock);
  
  static struct nfs_referral_count *nfs_find_referral_count(void)
  {
  	struct nfs_referral_count *p;
  
  	list_for_each_entry(p, &nfs_referral_count_list, list) {
  		if (p->task == current)
  			return p;
  	}
  	return NULL;
  }
  
  #define NFS_MAX_NESTED_REFERRALS 2
  
  static int nfs_referral_loop_protect(void)
  {
  	struct nfs_referral_count *p, *new;
  	int ret = -ENOMEM;
  
  	new = kmalloc(sizeof(*new), GFP_KERNEL);
  	if (!new)
  		goto out;
  	new->task = current;
  	new->referral_count = 1;
  
  	ret = 0;
  	spin_lock(&nfs_referral_count_list_lock);
  	p = nfs_find_referral_count();
  	if (p != NULL) {
  		if (p->referral_count >= NFS_MAX_NESTED_REFERRALS)
  			ret = -ELOOP;
  		else
  			p->referral_count++;
  	} else {
  		list_add(&new->list, &nfs_referral_count_list);
  		new = NULL;
  	}
  	spin_unlock(&nfs_referral_count_list_lock);
  	kfree(new);
  out:
  	return ret;
  }
  
  static void nfs_referral_loop_unprotect(void)
  {
  	struct nfs_referral_count *p;
  
  	spin_lock(&nfs_referral_count_list_lock);
  	p = nfs_find_referral_count();
  	p->referral_count--;
  	if (p->referral_count == 0)
  		list_del(&p->list);
  	else
  		p = NULL;
  	spin_unlock(&nfs_referral_count_list_lock);
  	kfree(p);
  }
011949811   Al Viro   nfs: switch NFS f...
2736
2737
  static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt,
  		const char *export_path)
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2738
  {
011949811   Al Viro   nfs: switch NFS f...
2739
  	struct dentry *dentry;
5352d3b65   Al Viro   make nfs_follow_r...
2740
  	int err;
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2741

5352d3b65   Al Viro   make nfs_follow_r...
2742
2743
2744
2745
2746
  	if (IS_ERR(root_mnt))
  		return ERR_CAST(root_mnt);
  
  	err = nfs_referral_loop_protect();
  	if (err) {
ea441d110   Al Viro   new helper: mount...
2747
  		mntput(root_mnt);
5352d3b65   Al Viro   make nfs_follow_r...
2748
  		return ERR_PTR(err);
ea441d110   Al Viro   new helper: mount...
2749
  	}
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2750

ea441d110   Al Viro   new helper: mount...
2751
2752
  	dentry = mount_subtree(root_mnt, export_path);
  	nfs_referral_loop_unprotect();
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2753

011949811   Al Viro   nfs: switch NFS f...
2754
  	return dentry;
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2755
  }
011949811   Al Viro   nfs: switch NFS f...
2756
2757
  static struct dentry *nfs4_try_mount(int flags, const char *dev_name,
  			 struct nfs_parsed_mount_data *data)
a6fe23be9   Chuck Lever   NFS: Move details...
2758
2759
2760
  {
  	char *export_path;
  	struct vfsmount *root_mnt;
011949811   Al Viro   nfs: switch NFS f...
2761
  	struct dentry *res;
a6fe23be9   Chuck Lever   NFS: Move details...
2762
2763
2764
2765
2766
2767
2768
2769
2770
  
  	dfprintk(MOUNT, "--> nfs4_try_mount()
  ");
  
  	export_path = data->nfs_server.export_path;
  	data->nfs_server.export_path = "/";
  	root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data,
  			data->nfs_server.hostname);
  	data->nfs_server.export_path = export_path;
5352d3b65   Al Viro   make nfs_follow_r...
2771
  	res = nfs_follow_remote_path(root_mnt, export_path);
a6fe23be9   Chuck Lever   NFS: Move details...
2772

011949811   Al Viro   nfs: switch NFS f...
2773
2774
2775
2776
2777
  	dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s
  ",
  			IS_ERR(res) ? PTR_ERR(res) : 0,
  			IS_ERR(res) ? " [error]" : "");
  	return res;
a6fe23be9   Chuck Lever   NFS: Move details...
2778
  }
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2779
2780
2781
  /*
   * Get the superblock for an NFS4 mountpoint
   */
011949811   Al Viro   nfs: switch NFS f...
2782
2783
  static struct dentry *nfs4_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *raw_data)
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2784
2785
  {
  	struct nfs_parsed_mount_data *data;
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2786
  	int error = -ENOMEM;
011949811   Al Viro   nfs: switch NFS f...
2787
  	struct dentry *res = ERR_PTR(-ENOMEM);
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2788

c5811dbdd   Trond Myklebust   NFS: Fix a defaul...
2789
  	data = nfs_alloc_parsed_mount_data(4);
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2790
  	if (data == NULL)
8a0d551a5   Jeff Layton   nfs: fix regressi...
2791
  		goto out;
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2792
2793
2794
  
  	/* Validate the mount data */
  	error = nfs4_validate_mount_data(raw_data, data, dev_name);
011949811   Al Viro   nfs: switch NFS f...
2795
2796
  	if (error < 0) {
  		res = ERR_PTR(error);
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2797
  		goto out;
011949811   Al Viro   nfs: switch NFS f...
2798
  	}
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2799

011949811   Al Viro   nfs: switch NFS f...
2800
2801
2802
  	res = nfs4_try_mount(flags, dev_name, data);
  	if (IS_ERR(res))
  		error = PTR_ERR(res);
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2803
2804
  
  out:
8a0d551a5   Jeff Layton   nfs: fix regressi...
2805
  	nfs_free_parsed_mount_data(data);
011949811   Al Viro   nfs: switch NFS f...
2806
2807
  	dprintk("<-- nfs4_mount() = %d%s
  ", error,
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2808
  			error != 0 ? " [error]" : "");
011949811   Al Viro   nfs: switch NFS f...
2809
  	return res;
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
2810
  }
f7b422b17   David Howells   NFS: Split fs/nfs...
2811
2812
2813
  static void nfs4_kill_super(struct super_block *sb)
  {
  	struct nfs_server *server = NFS_SB(sb);
0f3e66c6a   Andy Adamson   nfs41: destroy_se...
2814
2815
  	dprintk("--> %s
  ", __func__);
515d86117   Trond Myklebust   NFSv4: Clean up t...
2816
  	nfs_super_return_all_delegations(sb);
f7b422b17   David Howells   NFS: Split fs/nfs...
2817
  	kill_anon_super(sb);
08734048b   David Howells   NFS: Define and c...
2818
  	nfs_fscache_release_super_cookie(sb);
54ceac451   David Howells   NFS: Share NFS su...
2819
  	nfs_free_server(server);
0f3e66c6a   Andy Adamson   nfs41: destroy_se...
2820
2821
  	dprintk("<-- %s
  ", __func__);
f7b422b17   David Howells   NFS: Split fs/nfs...
2822
2823
2824
  }
  
  /*
54ceac451   David Howells   NFS: Share NFS su...
2825
   * Clone an NFS4 server record on xdev traversal (FSID-change)
f7b422b17   David Howells   NFS: Split fs/nfs...
2826
   */
31f43471e   Al Viro   convert simple ca...
2827
2828
2829
  static struct dentry *
  nfs4_xdev_mount(struct file_system_type *fs_type, int flags,
  		 const char *dev_name, void *raw_data)
f7b422b17   David Howells   NFS: Split fs/nfs...
2830
  {
54ceac451   David Howells   NFS: Share NFS su...
2831
2832
2833
2834
  	struct nfs_clone_mount *data = raw_data;
  	struct super_block *s;
  	struct nfs_server *server;
  	struct dentry *mntroot;
75180df2e   Trond Myklebust   NFS: Add the moun...
2835
  	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2836
2837
2838
  	struct nfs_sb_mountdata sb_mntdata = {
  		.mntflags = flags,
  	};
54ceac451   David Howells   NFS: Share NFS su...
2839
  	int error;
f7b422b17   David Howells   NFS: Split fs/nfs...
2840

31f43471e   Al Viro   convert simple ca...
2841
2842
  	dprintk("--> nfs4_xdev_mount()
  ");
f7b422b17   David Howells   NFS: Split fs/nfs...
2843

54ceac451   David Howells   NFS: Share NFS su...
2844
2845
2846
2847
2848
  	/* create a new volume representation */
  	server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
  	if (IS_ERR(server)) {
  		error = PTR_ERR(server);
  		goto out_err_noserver;
f7b422b17   David Howells   NFS: Split fs/nfs...
2849
  	}
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2850
  	sb_mntdata.server = server;
f7b422b17   David Howells   NFS: Split fs/nfs...
2851

75180df2e   Trond Myklebust   NFS: Add the moun...
2852
2853
  	if (server->flags & NFS4_MOUNT_UNSHARED)
  		compare_super = NULL;
fb2088ccc   Sachin Prabhu   nfs: Do not allow...
2854
2855
2856
  	/* -o noac implies -o sync */
  	if (server->flags & NFS_MOUNT_NOAC)
  		sb_mntdata.mntflags |= MS_SYNCHRONOUS;
54ceac451   David Howells   NFS: Share NFS su...
2857
  	/* Get a superblock - note that we may end up sharing one that already exists */
ec9a05c94   Andy Adamson   NFS: use correct ...
2858
  	s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
54ceac451   David Howells   NFS: Share NFS su...
2859
2860
2861
  	if (IS_ERR(s)) {
  		error = PTR_ERR(s);
  		goto out_err_nosb;
f7b422b17   David Howells   NFS: Split fs/nfs...
2862
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2863

54ceac451   David Howells   NFS: Share NFS su...
2864
2865
2866
  	if (s->s_fs_info != server) {
  		nfs_free_server(server);
  		server = NULL;
fa799759f   Miklos Szeredi   mm: bdi: expose t...
2867
2868
2869
  	} else {
  		error = nfs_bdi_register(server);
  		if (error)
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2870
  			goto error_splat_bdi;
54ceac451   David Howells   NFS: Share NFS su...
2871
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2872

54ceac451   David Howells   NFS: Share NFS su...
2873
2874
  	if (!s->s_root) {
  		/* initial superblock/root creation */
54ceac451   David Howells   NFS: Share NFS su...
2875
  		nfs4_clone_super(s, data->sb);
2df548063   David Howells   NFS: Propagate 'f...
2876
  		nfs_fscache_get_super_cookie(s, NULL, data);
54ceac451   David Howells   NFS: Share NFS su...
2877
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2878

0d5839ad0   Al Viro   nfs: propagate de...
2879
  	mntroot = nfs4_get_root(s, data->fh, dev_name);
54ceac451   David Howells   NFS: Share NFS su...
2880
2881
2882
2883
  	if (IS_ERR(mntroot)) {
  		error = PTR_ERR(mntroot);
  		goto error_splat_super;
  	}
e9cc6c234   Trond Myklebust   NFS: Fix a possib...
2884
2885
2886
2887
2888
  	if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
  		dput(mntroot);
  		error = -ESTALE;
  		goto error_splat_super;
  	}
f7b422b17   David Howells   NFS: Split fs/nfs...
2889

54ceac451   David Howells   NFS: Share NFS su...
2890
  	s->s_flags |= MS_ACTIVE;
54ceac451   David Howells   NFS: Share NFS su...
2891

46c8ac742   Eric Paris   nfs/lsm: make NFS...
2892
  	security_sb_clone_mnt_opts(data->sb, s);
31f43471e   Al Viro   convert simple ca...
2893
2894
2895
  	dprintk("<-- nfs4_xdev_mount() = 0
  ");
  	return mntroot;
54ceac451   David Howells   NFS: Share NFS su...
2896
2897
2898
2899
  
  out_err_nosb:
  	nfs_free_server(server);
  out_err_noserver:
31f43471e   Al Viro   convert simple ca...
2900
2901
2902
  	dprintk("<-- nfs4_xdev_mount() = %d [error]
  ", error);
  	return ERR_PTR(error);
54ceac451   David Howells   NFS: Share NFS su...
2903
2904
  
  error_splat_super:
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2905
2906
2907
  	if (server && !s->s_root)
  		bdi_unregister(&server->backing_dev_info);
  error_splat_bdi:
6f5bbff9a   Al Viro   Convert obvious p...
2908
  	deactivate_locked_super(s);
31f43471e   Al Viro   convert simple ca...
2909
2910
2911
  	dprintk("<-- nfs4_xdev_mount() = %d [splat]
  ", error);
  	return ERR_PTR(error);
f7b422b17   David Howells   NFS: Split fs/nfs...
2912
  }
31f43471e   Al Viro   convert simple ca...
2913
2914
2915
  static struct dentry *
  nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
  			   const char *dev_name, void *raw_data)
f7b422b17   David Howells   NFS: Split fs/nfs...
2916
2917
  {
  	struct nfs_clone_mount *data = raw_data;
54ceac451   David Howells   NFS: Share NFS su...
2918
2919
2920
  	struct super_block *s;
  	struct nfs_server *server;
  	struct dentry *mntroot;
4f727296d   Trond Myklebust   NFSv4: Reduce the...
2921
  	struct nfs_fh *mntfh;
75180df2e   Trond Myklebust   NFS: Add the moun...
2922
  	int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2923
2924
2925
  	struct nfs_sb_mountdata sb_mntdata = {
  		.mntflags = flags,
  	};
4f727296d   Trond Myklebust   NFSv4: Reduce the...
2926
  	int error = -ENOMEM;
54ceac451   David Howells   NFS: Share NFS su...
2927
2928
2929
  
  	dprintk("--> nfs4_referral_get_sb()
  ");
4f727296d   Trond Myklebust   NFSv4: Reduce the...
2930
2931
2932
  	mntfh = nfs_alloc_fhandle();
  	if (mntfh == NULL)
  		goto out_err_nofh;
54ceac451   David Howells   NFS: Share NFS su...
2933
  	/* create a new volume representation */
4f727296d   Trond Myklebust   NFSv4: Reduce the...
2934
  	server = nfs4_create_referral_server(data, mntfh);
54ceac451   David Howells   NFS: Share NFS su...
2935
2936
2937
2938
  	if (IS_ERR(server)) {
  		error = PTR_ERR(server);
  		goto out_err_noserver;
  	}
e89a5a43b   Trond Myklebust   NFS: Fix the moun...
2939
  	sb_mntdata.server = server;
54ceac451   David Howells   NFS: Share NFS su...
2940

75180df2e   Trond Myklebust   NFS: Add the moun...
2941
2942
  	if (server->flags & NFS4_MOUNT_UNSHARED)
  		compare_super = NULL;
fb2088ccc   Sachin Prabhu   nfs: Do not allow...
2943
2944
2945
  	/* -o noac implies -o sync */
  	if (server->flags & NFS_MOUNT_NOAC)
  		sb_mntdata.mntflags |= MS_SYNCHRONOUS;
54ceac451   David Howells   NFS: Share NFS su...
2946
  	/* Get a superblock - note that we may end up sharing one that already exists */
ec9a05c94   Andy Adamson   NFS: use correct ...
2947
  	s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
54ceac451   David Howells   NFS: Share NFS su...
2948
2949
2950
2951
2952
2953
2954
2955
  	if (IS_ERR(s)) {
  		error = PTR_ERR(s);
  		goto out_err_nosb;
  	}
  
  	if (s->s_fs_info != server) {
  		nfs_free_server(server);
  		server = NULL;
fa799759f   Miklos Szeredi   mm: bdi: expose t...
2956
2957
2958
  	} else {
  		error = nfs_bdi_register(server);
  		if (error)
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2959
  			goto error_splat_bdi;
54ceac451   David Howells   NFS: Share NFS su...
2960
2961
2962
2963
  	}
  
  	if (!s->s_root) {
  		/* initial superblock/root creation */
54ceac451   David Howells   NFS: Share NFS su...
2964
  		nfs4_fill_super(s);
2df548063   David Howells   NFS: Propagate 'f...
2965
  		nfs_fscache_get_super_cookie(s, NULL, data);
54ceac451   David Howells   NFS: Share NFS su...
2966
  	}
0d5839ad0   Al Viro   nfs: propagate de...
2967
  	mntroot = nfs4_get_root(s, mntfh, dev_name);
54ceac451   David Howells   NFS: Share NFS su...
2968
2969
2970
2971
  	if (IS_ERR(mntroot)) {
  		error = PTR_ERR(mntroot);
  		goto error_splat_super;
  	}
e9cc6c234   Trond Myklebust   NFS: Fix a possib...
2972
2973
2974
2975
2976
  	if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) {
  		dput(mntroot);
  		error = -ESTALE;
  		goto error_splat_super;
  	}
54ceac451   David Howells   NFS: Share NFS su...
2977
2978
  
  	s->s_flags |= MS_ACTIVE;
54ceac451   David Howells   NFS: Share NFS su...
2979

46c8ac742   Eric Paris   nfs/lsm: make NFS...
2980
  	security_sb_clone_mnt_opts(data->sb, s);
4f727296d   Trond Myklebust   NFSv4: Reduce the...
2981
  	nfs_free_fhandle(mntfh);
54ceac451   David Howells   NFS: Share NFS su...
2982
2983
  	dprintk("<-- nfs4_referral_get_sb() = 0
  ");
31f43471e   Al Viro   convert simple ca...
2984
  	return mntroot;
54ceac451   David Howells   NFS: Share NFS su...
2985
2986
2987
2988
  
  out_err_nosb:
  	nfs_free_server(server);
  out_err_noserver:
4f727296d   Trond Myklebust   NFSv4: Reduce the...
2989
2990
  	nfs_free_fhandle(mntfh);
  out_err_nofh:
54ceac451   David Howells   NFS: Share NFS su...
2991
2992
  	dprintk("<-- nfs4_referral_get_sb() = %d [error]
  ", error);
31f43471e   Al Viro   convert simple ca...
2993
  	return ERR_PTR(error);
54ceac451   David Howells   NFS: Share NFS su...
2994
2995
  
  error_splat_super:
cfbc0683a   NeilBrown   NFS: ensure bdi_u...
2996
2997
2998
  	if (server && !s->s_root)
  		bdi_unregister(&server->backing_dev_info);
  error_splat_bdi:
6f5bbff9a   Al Viro   Convert obvious p...
2999
  	deactivate_locked_super(s);
4f727296d   Trond Myklebust   NFSv4: Reduce the...
3000
  	nfs_free_fhandle(mntfh);
54ceac451   David Howells   NFS: Share NFS su...
3001
3002
  	dprintk("<-- nfs4_referral_get_sb() = %d [splat]
  ", error);
31f43471e   Al Viro   convert simple ca...
3003
  	return ERR_PTR(error);
f7b422b17   David Howells   NFS: Split fs/nfs...
3004
  }
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
3005
3006
3007
  /*
   * Create an NFS4 server record on referral traversal
   */
011949811   Al Viro   nfs: switch NFS f...
3008
3009
  static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
  		int flags, const char *dev_name, void *raw_data)
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
3010
3011
3012
3013
  {
  	struct nfs_clone_mount *data = raw_data;
  	char *export_path;
  	struct vfsmount *root_mnt;
011949811   Al Viro   nfs: switch NFS f...
3014
  	struct dentry *res;
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
3015

011949811   Al Viro   nfs: switch NFS f...
3016
3017
  	dprintk("--> nfs4_referral_mount()
  ");
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
3018
3019
3020
3021
3022
3023
3024
  
  	export_path = data->mnt_path;
  	data->mnt_path = "/";
  
  	root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
  			flags, data, data->hostname);
  	data->mnt_path = export_path;
5352d3b65   Al Viro   make nfs_follow_r...
3025
  	res = nfs_follow_remote_path(root_mnt, export_path);
011949811   Al Viro   nfs: switch NFS f...
3026
3027
3028
3029
3030
  	dprintk("<-- nfs4_referral_mount() = %ld%s
  ",
  			IS_ERR(res) ? PTR_ERR(res) : 0,
  			IS_ERR(res) ? " [error]" : "");
  	return res;
c02d7adf8   Trond Myklebust   NFSv4: Replace nf...
3031
  }
54ceac451   David Howells   NFS: Share NFS su...
3032
  #endif /* CONFIG_NFS_V4 */