aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2009-06-17 21:13:00 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-06-18 21:13:44 -0400
commit1f84603c0940d5bed17f7e4d2e0b2a4b8b8f1b81 (patch)
tree143956f878290e85de7c9130f465e862f587ee53 /fs/nfs
parent301933a0acfdec837fd8b4884093b3f0fff01d8a (diff)
parent4bf259e3ae5015e73282ba66716c4a917e1264ac (diff)
Merge branch 'devel-for-2.6.31' into for-2.6.31
Conflicts: fs/nfs/client.c fs/nfs/super.c
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/callback.c4
-rw-r--r--fs/nfs/client.c9
-rw-r--r--fs/nfs/delegation.c32
-rw-r--r--fs/nfs/file.c37
-rw-r--r--fs/nfs/internal.h8
-rw-r--r--fs/nfs/mount_clnt.c337
-rw-r--r--fs/nfs/nfs3acl.c2
-rw-r--r--fs/nfs/nfs4proc.c61
-rw-r--r--fs/nfs/nfs4state.c37
-rw-r--r--fs/nfs/nfsroot.c5
-rw-r--r--fs/nfs/super.c288
11 files changed, 610 insertions, 210 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index e69b8f61189e..7f604c7941fb 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -123,7 +123,9 @@ nfs4_callback_up(struct svc_serv *serv)
123 nfs_callback_tcpport6 = ret; 123 nfs_callback_tcpport6 = ret;
124 dprintk("NFS: Callback listener port = %u (af %u)\n", 124 dprintk("NFS: Callback listener port = %u (af %u)\n",
125 nfs_callback_tcpport6, PF_INET6); 125 nfs_callback_tcpport6, PF_INET6);
126 } else if (ret != -EAFNOSUPPORT) 126 } else if (ret == -EAFNOSUPPORT)
127 ret = 0;
128 else
127 goto out_err; 129 goto out_err;
128#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ 130#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
129 131
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 4f75ec593be8..c2d061675d80 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -116,6 +116,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
116{ 116{
117 struct nfs_client *clp; 117 struct nfs_client *clp;
118 struct rpc_cred *cred; 118 struct rpc_cred *cred;
119 int err = -ENOMEM;
119 120
120 if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) 121 if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
121 goto error_0; 122 goto error_0;
@@ -129,6 +130,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
129 clp->cl_addrlen = cl_init->addrlen; 130 clp->cl_addrlen = cl_init->addrlen;
130 131
131 if (cl_init->hostname) { 132 if (cl_init->hostname) {
133 err = -ENOMEM;
132 clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); 134 clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL);
133 if (!clp->cl_hostname) 135 if (!clp->cl_hostname)
134 goto error_cleanup; 136 goto error_cleanup;
@@ -159,7 +161,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
159error_cleanup: 161error_cleanup:
160 kfree(clp); 162 kfree(clp);
161error_0: 163error_0:
162 return NULL; 164 return ERR_PTR(err);
163} 165}
164 166
165static void nfs4_shutdown_client(struct nfs_client *clp) 167static void nfs4_shutdown_client(struct nfs_client *clp)
@@ -480,9 +482,10 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in
480 spin_unlock(&nfs_client_lock); 482 spin_unlock(&nfs_client_lock);
481 483
482 new = nfs_alloc_client(cl_init); 484 new = nfs_alloc_client(cl_init);
483 } while (new); 485 } while (!IS_ERR(new));
484 486
485 return ERR_PTR(-ENOMEM); 487 dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new));
488 return new;
486 489
487 /* install a new client and return with it unready */ 490 /* install a new client and return with it unready */
488install_client: 491install_client:
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 968225a88015..af05b918cb5b 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -68,29 +68,26 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
68{ 68{
69 struct inode *inode = state->inode; 69 struct inode *inode = state->inode;
70 struct file_lock *fl; 70 struct file_lock *fl;
71 int status; 71 int status = 0;
72
73 if (inode->i_flock == NULL)
74 goto out;
72 75
76 /* Protect inode->i_flock using the BKL */
77 lock_kernel();
73 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { 78 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
74 if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) 79 if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
75 continue; 80 continue;
76 if (nfs_file_open_context(fl->fl_file) != ctx) 81 if (nfs_file_open_context(fl->fl_file) != ctx)
77 continue; 82 continue;
83 unlock_kernel();
78 status = nfs4_lock_delegation_recall(state, fl); 84 status = nfs4_lock_delegation_recall(state, fl);
79 if (status >= 0) 85 if (status < 0)
80 continue; 86 goto out;
81 switch (status) { 87 lock_kernel();
82 default:
83 printk(KERN_ERR "%s: unhandled error %d.\n",
84 __func__, status);
85 case -NFS4ERR_EXPIRED:
86 /* kill_proc(fl->fl_pid, SIGLOST, 1); */
87 case -NFS4ERR_STALE_CLIENTID:
88 nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client);
89 goto out_err;
90 }
91 } 88 }
92 return 0; 89 unlock_kernel();
93out_err: 90out:
94 return status; 91 return status;
95} 92}
96 93
@@ -268,7 +265,10 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
268 struct nfs_inode *nfsi = NFS_I(inode); 265 struct nfs_inode *nfsi = NFS_I(inode);
269 266
270 nfs_msync_inode(inode); 267 nfs_msync_inode(inode);
271 /* Guard against new delegated open calls */ 268 /*
269 * Guard against new delegated open/lock/unlock calls and against
270 * state recovery
271 */
272 down_write(&nfsi->rwsem); 272 down_write(&nfsi->rwsem);
273 nfs_delegation_claim_opens(inode, &delegation->stateid); 273 nfs_delegation_claim_opens(inode, &delegation->stateid);
274 up_write(&nfsi->rwsem); 274 up_write(&nfsi->rwsem);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index ec7e27d00bc6..0055b813ec2c 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -48,6 +48,9 @@ static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos,
48 size_t count, unsigned int flags); 48 size_t count, unsigned int flags);
49static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, 49static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
50 unsigned long nr_segs, loff_t pos); 50 unsigned long nr_segs, loff_t pos);
51static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
52 struct file *filp, loff_t *ppos,
53 size_t count, unsigned int flags);
51static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, 54static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
52 unsigned long nr_segs, loff_t pos); 55 unsigned long nr_segs, loff_t pos);
53static int nfs_file_flush(struct file *, fl_owner_t id); 56static int nfs_file_flush(struct file *, fl_owner_t id);
@@ -73,6 +76,7 @@ const struct file_operations nfs_file_operations = {
73 .lock = nfs_lock, 76 .lock = nfs_lock,
74 .flock = nfs_flock, 77 .flock = nfs_flock,
75 .splice_read = nfs_file_splice_read, 78 .splice_read = nfs_file_splice_read,
79 .splice_write = nfs_file_splice_write,
76 .check_flags = nfs_check_flags, 80 .check_flags = nfs_check_flags,
77 .setlease = nfs_setlease, 81 .setlease = nfs_setlease,
78}; 82};
@@ -587,12 +591,38 @@ out_swapfile:
587 goto out; 591 goto out;
588} 592}
589 593
594static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
595 struct file *filp, loff_t *ppos,
596 size_t count, unsigned int flags)
597{
598 struct dentry *dentry = filp->f_path.dentry;
599 struct inode *inode = dentry->d_inode;
600 ssize_t ret;
601
602 dprintk("NFS splice_write(%s/%s, %lu@%llu)\n",
603 dentry->d_parent->d_name.name, dentry->d_name.name,
604 (unsigned long) count, (unsigned long long) *ppos);
605
606 /*
607 * The combination of splice and an O_APPEND destination is disallowed.
608 */
609
610 nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
611
612 ret = generic_file_splice_write(pipe, filp, ppos, count, flags);
613 if (ret >= 0 && nfs_need_sync_write(filp, inode)) {
614 int err = nfs_do_fsync(nfs_file_open_context(filp), inode);
615 if (err < 0)
616 ret = err;
617 }
618 return ret;
619}
620
590static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) 621static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
591{ 622{
592 struct inode *inode = filp->f_mapping->host; 623 struct inode *inode = filp->f_mapping->host;
593 int status = 0; 624 int status = 0;
594 625
595 lock_kernel();
596 /* Try local locking first */ 626 /* Try local locking first */
597 posix_test_lock(filp, fl); 627 posix_test_lock(filp, fl);
598 if (fl->fl_type != F_UNLCK) { 628 if (fl->fl_type != F_UNLCK) {
@@ -608,7 +638,6 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
608 638
609 status = NFS_PROTO(inode)->lock(filp, cmd, fl); 639 status = NFS_PROTO(inode)->lock(filp, cmd, fl);
610out: 640out:
611 unlock_kernel();
612 return status; 641 return status;
613out_noconflict: 642out_noconflict:
614 fl->fl_type = F_UNLCK; 643 fl->fl_type = F_UNLCK;
@@ -650,13 +679,11 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
650 * If we're signalled while cleaning up locks on process exit, we 679 * If we're signalled while cleaning up locks on process exit, we
651 * still need to complete the unlock. 680 * still need to complete the unlock.
652 */ 681 */
653 lock_kernel();
654 /* Use local locking if mounted with "-onolock" */ 682 /* Use local locking if mounted with "-onolock" */
655 if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) 683 if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
656 status = NFS_PROTO(inode)->lock(filp, cmd, fl); 684 status = NFS_PROTO(inode)->lock(filp, cmd, fl);
657 else 685 else
658 status = do_vfs_lock(filp, fl); 686 status = do_vfs_lock(filp, fl);
659 unlock_kernel();
660 return status; 687 return status;
661} 688}
662 689
@@ -673,13 +700,11 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
673 if (status != 0) 700 if (status != 0)
674 goto out; 701 goto out;
675 702
676 lock_kernel();
677 /* Use local locking if mounted with "-onolock" */ 703 /* Use local locking if mounted with "-onolock" */
678 if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) 704 if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
679 status = NFS_PROTO(inode)->lock(filp, cmd, fl); 705 status = NFS_PROTO(inode)->lock(filp, cmd, fl);
680 else 706 else
681 status = do_vfs_lock(filp, fl); 707 status = do_vfs_lock(filp, fl);
682 unlock_kernel();
683 if (status < 0) 708 if (status < 0)
684 goto out; 709 goto out;
685 /* 710 /*
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index acee3274d275..7dd90a6769d0 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -43,6 +43,12 @@ struct nfs_clone_mount {
43}; 43};
44 44
45/* 45/*
46 * Note: RFC 1813 doesn't limit the number of auth flavors that
47 * a server can return, so make something up.
48 */
49#define NFS_MAX_SECFLAVORS (12)
50
51/*
46 * In-kernel mount arguments 52 * In-kernel mount arguments
47 */ 53 */
48struct nfs_parsed_mount_data { 54struct nfs_parsed_mount_data {
@@ -91,6 +97,8 @@ struct nfs_mount_request {
91 unsigned short protocol; 97 unsigned short protocol;
92 struct nfs_fh *fh; 98 struct nfs_fh *fh;
93 int noresvport; 99 int noresvport;
100 unsigned int *auth_flav_len;
101 rpc_authflavor_t *auth_flavs;
94}; 102};
95 103
96extern int nfs_mount(struct nfs_mount_request *info); 104extern int nfs_mount(struct nfs_mount_request *info);
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index ca905a5bb1ba..38ef9eaec407 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -20,8 +20,116 @@
20# define NFSDBG_FACILITY NFSDBG_MOUNT 20# define NFSDBG_FACILITY NFSDBG_MOUNT
21#endif 21#endif
22 22
23/*
24 * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4
25 */
26#define MNTPATHLEN (1024)
27
28/*
29 * XDR data type sizes
30 */
31#define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN))
32#define MNT_status_sz (1)
33#define MNT_fhs_status_sz (1)
34#define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE)
35#define MNT_fhandle3_sz (1 + XDR_QUADLEN(NFS3_FHSIZE))
36#define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS)
37
38/*
39 * XDR argument and result sizes
40 */
41#define MNT_enc_dirpath_sz encode_dirpath_sz
42#define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz)
43#define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandle_sz + \
44 MNT_authflav3_sz)
45
46/*
47 * Defined by RFC 1094, section A.5
48 */
49enum {
50 MOUNTPROC_NULL = 0,
51 MOUNTPROC_MNT = 1,
52 MOUNTPROC_DUMP = 2,
53 MOUNTPROC_UMNT = 3,
54 MOUNTPROC_UMNTALL = 4,
55 MOUNTPROC_EXPORT = 5,
56};
57
58/*
59 * Defined by RFC 1813, section 5.2
60 */
61enum {
62 MOUNTPROC3_NULL = 0,
63 MOUNTPROC3_MNT = 1,
64 MOUNTPROC3_DUMP = 2,
65 MOUNTPROC3_UMNT = 3,
66 MOUNTPROC3_UMNTALL = 4,
67 MOUNTPROC3_EXPORT = 5,
68};
69
23static struct rpc_program mnt_program; 70static struct rpc_program mnt_program;
24 71
72/*
73 * Defined by OpenGroup XNFS Version 3W, chapter 8
74 */
75enum mountstat {
76 MNT_OK = 0,
77 MNT_EPERM = 1,
78 MNT_ENOENT = 2,
79 MNT_EACCES = 13,
80 MNT_EINVAL = 22,
81};
82
83static struct {
84 u32 status;
85 int errno;
86} mnt_errtbl[] = {
87 { .status = MNT_OK, .errno = 0, },
88 { .status = MNT_EPERM, .errno = -EPERM, },
89 { .status = MNT_ENOENT, .errno = -ENOENT, },
90 { .status = MNT_EACCES, .errno = -EACCES, },
91 { .status = MNT_EINVAL, .errno = -EINVAL, },
92};
93
94/*
95 * Defined by RFC 1813, section 5.1.5
96 */
97enum mountstat3 {
98 MNT3_OK = 0, /* no error */
99 MNT3ERR_PERM = 1, /* Not owner */
100 MNT3ERR_NOENT = 2, /* No such file or directory */
101 MNT3ERR_IO = 5, /* I/O error */
102 MNT3ERR_ACCES = 13, /* Permission denied */
103 MNT3ERR_NOTDIR = 20, /* Not a directory */
104 MNT3ERR_INVAL = 22, /* Invalid argument */
105 MNT3ERR_NAMETOOLONG = 63, /* Filename too long */
106 MNT3ERR_NOTSUPP = 10004, /* Operation not supported */
107 MNT3ERR_SERVERFAULT = 10006, /* A failure on the server */
108};
109
110static struct {
111 u32 status;
112 int errno;
113} mnt3_errtbl[] = {
114 { .status = MNT3_OK, .errno = 0, },
115 { .status = MNT3ERR_PERM, .errno = -EPERM, },
116 { .status = MNT3ERR_NOENT, .errno = -ENOENT, },
117 { .status = MNT3ERR_IO, .errno = -EIO, },
118 { .status = MNT3ERR_ACCES, .errno = -EACCES, },
119 { .status = MNT3ERR_NOTDIR, .errno = -ENOTDIR, },
120 { .status = MNT3ERR_INVAL, .errno = -EINVAL, },
121 { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, },
122 { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, },
123 { .status = MNT3ERR_SERVERFAULT, .errno = -ESERVERFAULT, },
124};
125
126struct mountres {
127 int errno;
128 struct nfs_fh *fh;
129 unsigned int *auth_count;
130 rpc_authflavor_t *auth_flavors;
131};
132
25struct mnt_fhstatus { 133struct mnt_fhstatus {
26 u32 status; 134 u32 status;
27 struct nfs_fh *fh; 135 struct nfs_fh *fh;
@@ -35,8 +143,10 @@ struct mnt_fhstatus {
35 */ 143 */
36int nfs_mount(struct nfs_mount_request *info) 144int nfs_mount(struct nfs_mount_request *info)
37{ 145{
38 struct mnt_fhstatus result = { 146 struct mountres result = {
39 .fh = info->fh 147 .fh = info->fh,
148 .auth_count = info->auth_flav_len,
149 .auth_flavors = info->auth_flavs,
40 }; 150 };
41 struct rpc_message msg = { 151 struct rpc_message msg = {
42 .rpc_argp = info->dirpath, 152 .rpc_argp = info->dirpath,
@@ -68,14 +178,14 @@ int nfs_mount(struct nfs_mount_request *info)
68 if (info->version == NFS_MNT3_VERSION) 178 if (info->version == NFS_MNT3_VERSION)
69 msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; 179 msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
70 else 180 else
71 msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; 181 msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
72 182
73 status = rpc_call_sync(mnt_clnt, &msg, 0); 183 status = rpc_call_sync(mnt_clnt, &msg, 0);
74 rpc_shutdown_client(mnt_clnt); 184 rpc_shutdown_client(mnt_clnt);
75 185
76 if (status < 0) 186 if (status < 0)
77 goto out_call_err; 187 goto out_call_err;
78 if (result.status != 0) 188 if (result.errno != 0)
79 goto out_mnt_err; 189 goto out_mnt_err;
80 190
81 dprintk("NFS: MNT request succeeded\n"); 191 dprintk("NFS: MNT request succeeded\n");
@@ -86,72 +196,215 @@ out:
86 196
87out_clnt_err: 197out_clnt_err:
88 status = PTR_ERR(mnt_clnt); 198 status = PTR_ERR(mnt_clnt);
89 dprintk("NFS: failed to create RPC client, status=%d\n", status); 199 dprintk("NFS: failed to create MNT RPC client, status=%d\n", status);
90 goto out; 200 goto out;
91 201
92out_call_err: 202out_call_err:
93 dprintk("NFS: failed to start MNT request, status=%d\n", status); 203 dprintk("NFS: MNT request failed, status=%d\n", status);
94 goto out; 204 goto out;
95 205
96out_mnt_err: 206out_mnt_err:
97 dprintk("NFS: MNT server returned result %d\n", result.status); 207 dprintk("NFS: MNT server returned result %d\n", result.errno);
98 status = nfs_stat_to_errno(result.status); 208 status = result.errno;
99 goto out; 209 goto out;
100} 210}
101 211
102/* 212/*
103 * XDR encode/decode functions for MOUNT 213 * XDR encode/decode functions for MOUNT
104 */ 214 */
105static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, 215
106 const char *path) 216static int encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
217{
218 const u32 pathname_len = strlen(pathname);
219 __be32 *p;
220
221 if (unlikely(pathname_len > MNTPATHLEN))
222 return -EIO;
223
224 p = xdr_reserve_space(xdr, sizeof(u32) + pathname_len);
225 if (unlikely(p == NULL))
226 return -EIO;
227 xdr_encode_opaque(p, pathname, pathname_len);
228
229 return 0;
230}
231
232static int mnt_enc_dirpath(struct rpc_rqst *req, __be32 *p,
233 const char *dirpath)
234{
235 struct xdr_stream xdr;
236
237 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
238 return encode_mntdirpath(&xdr, dirpath);
239}
240
241/*
242 * RFC 1094: "A non-zero status indicates some sort of error. In this
243 * case, the status is a UNIX error number." This can be problematic
244 * if the server and client use different errno values for the same
245 * error.
246 *
247 * However, the OpenGroup XNFS spec provides a simple mapping that is
248 * independent of local errno values on the server and the client.
249 */
250static int decode_status(struct xdr_stream *xdr, struct mountres *res)
107{ 251{
108 p = xdr_encode_string(p, path); 252 unsigned int i;
253 u32 status;
254 __be32 *p;
255
256 p = xdr_inline_decode(xdr, sizeof(status));
257 if (unlikely(p == NULL))
258 return -EIO;
259 status = ntohl(*p);
109 260
110 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 261 for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) {
262 if (mnt_errtbl[i].status == status) {
263 res->errno = mnt_errtbl[i].errno;
264 return 0;
265 }
266 }
267
268 dprintk("NFS: unrecognized MNT status code: %u\n", status);
269 res->errno = -EACCES;
111 return 0; 270 return 0;
112} 271}
113 272
114static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, 273static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
115 struct mnt_fhstatus *res)
116{ 274{
117 struct nfs_fh *fh = res->fh; 275 struct nfs_fh *fh = res->fh;
276 __be32 *p;
277
278 p = xdr_inline_decode(xdr, NFS2_FHSIZE);
279 if (unlikely(p == NULL))
280 return -EIO;
281
282 fh->size = NFS2_FHSIZE;
283 memcpy(fh->data, p, NFS2_FHSIZE);
284 return 0;
285}
286
287static int mnt_dec_mountres(struct rpc_rqst *req, __be32 *p,
288 struct mountres *res)
289{
290 struct xdr_stream xdr;
291 int status;
292
293 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
294
295 status = decode_status(&xdr, res);
296 if (unlikely(status != 0 || res->errno != 0))
297 return status;
298 return decode_fhandle(&xdr, res);
299}
300
301static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)
302{
303 unsigned int i;
304 u32 status;
305 __be32 *p;
118 306
119 if ((res->status = ntohl(*p++)) == 0) { 307 p = xdr_inline_decode(xdr, sizeof(status));
120 fh->size = NFS2_FHSIZE; 308 if (unlikely(p == NULL))
121 memcpy(fh->data, p, NFS2_FHSIZE); 309 return -EIO;
310 status = ntohl(*p);
311
312 for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) {
313 if (mnt3_errtbl[i].status == status) {
314 res->errno = mnt3_errtbl[i].errno;
315 return 0;
316 }
122 } 317 }
318
319 dprintk("NFS: unrecognized MNT3 status code: %u\n", status);
320 res->errno = -EACCES;
123 return 0; 321 return 0;
124} 322}
125 323
126static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, 324static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res)
127 struct mnt_fhstatus *res)
128{ 325{
129 struct nfs_fh *fh = res->fh; 326 struct nfs_fh *fh = res->fh;
130 unsigned size; 327 u32 size;
131 328 __be32 *p;
132 if ((res->status = ntohl(*p++)) == 0) { 329
133 size = ntohl(*p++); 330 p = xdr_inline_decode(xdr, sizeof(size));
134 if (size <= NFS3_FHSIZE && size != 0) { 331 if (unlikely(p == NULL))
135 fh->size = size; 332 return -EIO;
136 memcpy(fh->data, p, size); 333
137 } else 334 size = ntohl(*p++);
138 res->status = -EBADHANDLE; 335 if (size > NFS3_FHSIZE || size == 0)
336 return -EIO;
337
338 p = xdr_inline_decode(xdr, size);
339 if (unlikely(p == NULL))
340 return -EIO;
341
342 fh->size = size;
343 memcpy(fh->data, p, size);
344 return 0;
345}
346
347static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
348{
349 rpc_authflavor_t *flavors = res->auth_flavors;
350 unsigned int *count = res->auth_count;
351 u32 entries, i;
352 __be32 *p;
353
354 if (*count == 0)
355 return 0;
356
357 p = xdr_inline_decode(xdr, sizeof(entries));
358 if (unlikely(p == NULL))
359 return -EIO;
360 entries = ntohl(*p);
361 dprintk("NFS: received %u auth flavors\n", entries);
362 if (entries > NFS_MAX_SECFLAVORS)
363 entries = NFS_MAX_SECFLAVORS;
364
365 p = xdr_inline_decode(xdr, sizeof(u32) * entries);
366 if (unlikely(p == NULL))
367 return -EIO;
368
369 if (entries > *count)
370 entries = *count;
371
372 for (i = 0; i < entries; i++) {
373 flavors[i] = ntohl(*p++);
374 dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]);
139 } 375 }
376 *count = i;
377
140 return 0; 378 return 0;
141} 379}
142 380
143#define MNT_dirpath_sz (1 + 256) 381static int mnt_dec_mountres3(struct rpc_rqst *req, __be32 *p,
144#define MNT_fhstatus_sz (1 + 8) 382 struct mountres *res)
145#define MNT_fhstatus3_sz (1 + 16) 383{
384 struct xdr_stream xdr;
385 int status;
386
387 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
388
389 status = decode_fhs_status(&xdr, res);
390 if (unlikely(status != 0 || res->errno != 0))
391 return status;
392 status = decode_fhandle3(&xdr, res);
393 if (unlikely(status != 0)) {
394 res->errno = -EBADHANDLE;
395 return 0;
396 }
397 return decode_auth_flavors(&xdr, res);
398}
146 399
147static struct rpc_procinfo mnt_procedures[] = { 400static struct rpc_procinfo mnt_procedures[] = {
148 [MNTPROC_MNT] = { 401 [MOUNTPROC_MNT] = {
149 .p_proc = MNTPROC_MNT, 402 .p_proc = MOUNTPROC_MNT,
150 .p_encode = (kxdrproc_t) xdr_encode_dirpath, 403 .p_encode = (kxdrproc_t)mnt_enc_dirpath,
151 .p_decode = (kxdrproc_t) xdr_decode_fhstatus, 404 .p_decode = (kxdrproc_t)mnt_dec_mountres,
152 .p_arglen = MNT_dirpath_sz, 405 .p_arglen = MNT_enc_dirpath_sz,
153 .p_replen = MNT_fhstatus_sz, 406 .p_replen = MNT_dec_mountres_sz,
154 .p_statidx = MNTPROC_MNT, 407 .p_statidx = MOUNTPROC_MNT,
155 .p_name = "MOUNT", 408 .p_name = "MOUNT",
156 }, 409 },
157}; 410};
@@ -159,10 +412,10 @@ static struct rpc_procinfo mnt_procedures[] = {
159static struct rpc_procinfo mnt3_procedures[] = { 412static struct rpc_procinfo mnt3_procedures[] = {
160 [MOUNTPROC3_MNT] = { 413 [MOUNTPROC3_MNT] = {
161 .p_proc = MOUNTPROC3_MNT, 414 .p_proc = MOUNTPROC3_MNT,
162 .p_encode = (kxdrproc_t) xdr_encode_dirpath, 415 .p_encode = (kxdrproc_t)mnt_enc_dirpath,
163 .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, 416 .p_decode = (kxdrproc_t)mnt_dec_mountres3,
164 .p_arglen = MNT_dirpath_sz, 417 .p_arglen = MNT_enc_dirpath_sz,
165 .p_replen = MNT_fhstatus3_sz, 418 .p_replen = MNT_dec_mountres3_sz,
166 .p_statidx = MOUNTPROC3_MNT, 419 .p_statidx = MOUNTPROC3_MNT,
167 .p_name = "MOUNT", 420 .p_name = "MOUNT",
168 }, 421 },
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 6bbf0e6daad2..bac60515a4b3 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -207,8 +207,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
207 status = nfs_revalidate_inode(server, inode); 207 status = nfs_revalidate_inode(server, inode);
208 if (status < 0) 208 if (status < 0)
209 return ERR_PTR(status); 209 return ERR_PTR(status);
210 if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
211 nfs_zap_acl_cache(inode);
212 acl = nfs3_get_cached_acl(inode, type); 210 acl = nfs3_get_cached_acl(inode, type);
213 if (acl != ERR_PTR(-EAGAIN)) 211 if (acl != ERR_PTR(-EAGAIN))
214 return acl; 212 return acl;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 57dabb8a048e..7a750f061c26 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1173,16 +1173,30 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
1173 err = _nfs4_open_delegation_recall(ctx, state, stateid); 1173 err = _nfs4_open_delegation_recall(ctx, state, stateid);
1174 switch (err) { 1174 switch (err) {
1175 case 0: 1175 case 0:
1176 return err; 1176 case -ENOENT:
1177 case -ESTALE:
1178 goto out;
1177 case -NFS4ERR_STALE_CLIENTID: 1179 case -NFS4ERR_STALE_CLIENTID:
1178 case -NFS4ERR_STALE_STATEID: 1180 case -NFS4ERR_STALE_STATEID:
1179 case -NFS4ERR_EXPIRED: 1181 case -NFS4ERR_EXPIRED:
1180 /* Don't recall a delegation if it was lost */ 1182 /* Don't recall a delegation if it was lost */
1181 nfs4_schedule_state_recovery(server->nfs_client); 1183 nfs4_schedule_state_recovery(server->nfs_client);
1182 return err; 1184 goto out;
1185 case -ERESTARTSYS:
1186 /*
1187 * The show must go on: exit, but mark the
1188 * stateid as needing recovery.
1189 */
1190 case -NFS4ERR_ADMIN_REVOKED:
1191 case -NFS4ERR_BAD_STATEID:
1192 nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
1193 case -ENOMEM:
1194 err = 0;
1195 goto out;
1183 } 1196 }
1184 err = nfs4_handle_exception(server, err, &exception); 1197 err = nfs4_handle_exception(server, err, &exception);
1185 } while (exception.retry); 1198 } while (exception.retry);
1199out:
1186 return err; 1200 return err;
1187} 1201}
1188 1202
@@ -3238,8 +3252,6 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
3238 ret = nfs_revalidate_inode(server, inode); 3252 ret = nfs_revalidate_inode(server, inode);
3239 if (ret < 0) 3253 if (ret < 0)
3240 return ret; 3254 return ret;
3241 if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
3242 nfs_zap_acl_cache(inode);
3243 ret = nfs4_read_cached_acl(inode, buf, buflen); 3255 ret = nfs4_read_cached_acl(inode, buf, buflen);
3244 if (ret != -ENOENT) 3256 if (ret != -ENOENT)
3245 return ret; 3257 return ret;
@@ -3977,8 +3989,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
3977 ret = nfs4_wait_for_completion_rpc_task(task); 3989 ret = nfs4_wait_for_completion_rpc_task(task);
3978 if (ret == 0) { 3990 if (ret == 0) {
3979 ret = data->rpc_status; 3991 ret = data->rpc_status;
3980 if (ret == -NFS4ERR_DENIED)
3981 ret = -EAGAIN;
3982 } else 3992 } else
3983 data->cancelled = 1; 3993 data->cancelled = 1;
3984 rpc_put_task(task); 3994 rpc_put_task(task);
@@ -4066,9 +4076,11 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
4066 int err; 4076 int err;
4067 4077
4068 do { 4078 do {
4079 err = _nfs4_proc_setlk(state, cmd, request);
4080 if (err == -NFS4ERR_DENIED)
4081 err = -EAGAIN;
4069 err = nfs4_handle_exception(NFS_SERVER(state->inode), 4082 err = nfs4_handle_exception(NFS_SERVER(state->inode),
4070 _nfs4_proc_setlk(state, cmd, request), 4083 err, &exception);
4071 &exception);
4072 } while (exception.retry); 4084 } while (exception.retry);
4073 return err; 4085 return err;
4074} 4086}
@@ -4120,8 +4132,37 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
4120 goto out; 4132 goto out;
4121 do { 4133 do {
4122 err = _nfs4_do_setlk(state, F_SETLK, fl, 0); 4134 err = _nfs4_do_setlk(state, F_SETLK, fl, 0);
4123 if (err != -NFS4ERR_DELAY) 4135 switch (err) {
4124 break; 4136 default:
4137 printk(KERN_ERR "%s: unhandled error %d.\n",
4138 __func__, err);
4139 case 0:
4140 case -ESTALE:
4141 goto out;
4142 case -NFS4ERR_EXPIRED:
4143 case -NFS4ERR_STALE_CLIENTID:
4144 case -NFS4ERR_STALE_STATEID:
4145 nfs4_schedule_state_recovery(server->nfs_client);
4146 goto out;
4147 case -ERESTARTSYS:
4148 /*
4149 * The show must go on: exit, but mark the
4150 * stateid as needing recovery.
4151 */
4152 case -NFS4ERR_ADMIN_REVOKED:
4153 case -NFS4ERR_BAD_STATEID:
4154 case -NFS4ERR_OPENMODE:
4155 nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
4156 err = 0;
4157 goto out;
4158 case -ENOMEM:
4159 case -NFS4ERR_DENIED:
4160 /* kill_proc(fl->fl_pid, SIGLOST, 1); */
4161 err = 0;
4162 goto out;
4163 case -NFS4ERR_DELAY:
4164 break;
4165 }
4125 err = nfs4_handle_exception(server, err, &exception); 4166 err = nfs4_handle_exception(server, err, &exception);
4126 } while (exception.retry); 4167 } while (exception.retry);
4127out: 4168out:
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 2cfca9929c9a..b73c5a728655 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -853,32 +853,45 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
853 struct file_lock *fl; 853 struct file_lock *fl;
854 int status = 0; 854 int status = 0;
855 855
856 if (inode->i_flock == NULL)
857 return 0;
858
859 /* Guard against delegation returns and new lock/unlock calls */
856 down_write(&nfsi->rwsem); 860 down_write(&nfsi->rwsem);
861 /* Protect inode->i_flock using the BKL */
862 lock_kernel();
857 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { 863 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
858 if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) 864 if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
859 continue; 865 continue;
860 if (nfs_file_open_context(fl->fl_file)->state != state) 866 if (nfs_file_open_context(fl->fl_file)->state != state)
861 continue; 867 continue;
868 unlock_kernel();
862 status = ops->recover_lock(state, fl); 869 status = ops->recover_lock(state, fl);
863 if (status >= 0)
864 continue;
865 switch (status) { 870 switch (status) {
871 case 0:
872 break;
873 case -ESTALE:
874 case -NFS4ERR_ADMIN_REVOKED:
875 case -NFS4ERR_STALE_STATEID:
876 case -NFS4ERR_BAD_STATEID:
877 case -NFS4ERR_EXPIRED:
878 case -NFS4ERR_NO_GRACE:
879 case -NFS4ERR_STALE_CLIENTID:
880 goto out;
866 default: 881 default:
867 printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", 882 printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
868 __func__, status); 883 __func__, status);
869 case -NFS4ERR_EXPIRED: 884 case -ENOMEM:
870 case -NFS4ERR_NO_GRACE: 885 case -NFS4ERR_DENIED:
871 case -NFS4ERR_RECLAIM_BAD: 886 case -NFS4ERR_RECLAIM_BAD:
872 case -NFS4ERR_RECLAIM_CONFLICT: 887 case -NFS4ERR_RECLAIM_CONFLICT:
873 /* kill_proc(fl->fl_pid, SIGLOST, 1); */ 888 /* kill_proc(fl->fl_pid, SIGLOST, 1); */
874 break; 889 status = 0;
875 case -NFS4ERR_STALE_CLIENTID:
876 goto out_err;
877 } 890 }
891 lock_kernel();
878 } 892 }
879 up_write(&nfsi->rwsem); 893 unlock_kernel();
880 return 0; 894out:
881out_err:
882 up_write(&nfsi->rwsem); 895 up_write(&nfsi->rwsem);
883 return status; 896 return status;
884} 897}
@@ -924,6 +937,7 @@ restart:
924 printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", 937 printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
925 __func__, status); 938 __func__, status);
926 case -ENOENT: 939 case -ENOENT:
940 case -ENOMEM:
927 case -ESTALE: 941 case -ESTALE:
928 /* 942 /*
929 * Open state on this file cannot be recovered 943 * Open state on this file cannot be recovered
@@ -934,6 +948,9 @@ restart:
934 /* Mark the file as being 'closed' */ 948 /* Mark the file as being 'closed' */
935 state->state = 0; 949 state->state = 0;
936 break; 950 break;
951 case -NFS4ERR_ADMIN_REVOKED:
952 case -NFS4ERR_STALE_STATEID:
953 case -NFS4ERR_BAD_STATEID:
937 case -NFS4ERR_RECLAIM_BAD: 954 case -NFS4ERR_RECLAIM_BAD:
938 case -NFS4ERR_RECLAIM_CONFLICT: 955 case -NFS4ERR_RECLAIM_CONFLICT:
939 nfs4_state_mark_reclaim_nograce(sp->so_client, state); 956 nfs4_state_mark_reclaim_nograce(sp->so_client, state);
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index e3ed5908820b..8c55b27c0de4 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -92,6 +92,9 @@
92#undef NFSROOT_DEBUG 92#undef NFSROOT_DEBUG
93#define NFSDBG_FACILITY NFSDBG_ROOT 93#define NFSDBG_FACILITY NFSDBG_ROOT
94 94
95/* Default port to use if server is not running a portmapper */
96#define NFS_MNT_PORT 627
97
95/* Default path we try to mount. "%s" gets replaced by our IP address */ 98/* Default path we try to mount. "%s" gets replaced by our IP address */
96#define NFS_ROOT "/tftpboot/%s" 99#define NFS_ROOT "/tftpboot/%s"
97 100
@@ -487,6 +490,7 @@ static int __init root_nfs_get_handle(void)
487{ 490{
488 struct nfs_fh fh; 491 struct nfs_fh fh;
489 struct sockaddr_in sin; 492 struct sockaddr_in sin;
493 unsigned int auth_flav_len = 0;
490 struct nfs_mount_request request = { 494 struct nfs_mount_request request = {
491 .sap = (struct sockaddr *)&sin, 495 .sap = (struct sockaddr *)&sin,
492 .salen = sizeof(sin), 496 .salen = sizeof(sin),
@@ -496,6 +500,7 @@ static int __init root_nfs_get_handle(void)
496 .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? 500 .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
497 XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, 501 XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP,
498 .fh = &fh, 502 .fh = &fh,
503 .auth_flav_len = &auth_flav_len,
499 }; 504 };
500 int status; 505 int status;
501 506
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 6063054455f8..3d460527daab 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -140,22 +140,22 @@ static const match_table_t nfs_mount_option_tokens = {
140 { Opt_fscache_uniq, "fsc=%s" }, 140 { Opt_fscache_uniq, "fsc=%s" },
141 { Opt_nofscache, "nofsc" }, 141 { Opt_nofscache, "nofsc" },
142 142
143 { Opt_port, "port=%u" }, 143 { Opt_port, "port=%s" },
144 { Opt_rsize, "rsize=%u" }, 144 { Opt_rsize, "rsize=%s" },
145 { Opt_wsize, "wsize=%u" }, 145 { Opt_wsize, "wsize=%s" },
146 { Opt_bsize, "bsize=%u" }, 146 { Opt_bsize, "bsize=%s" },
147 { Opt_timeo, "timeo=%u" }, 147 { Opt_timeo, "timeo=%s" },
148 { Opt_retrans, "retrans=%u" }, 148 { Opt_retrans, "retrans=%s" },
149 { Opt_acregmin, "acregmin=%u" }, 149 { Opt_acregmin, "acregmin=%s" },
150 { Opt_acregmax, "acregmax=%u" }, 150 { Opt_acregmax, "acregmax=%s" },
151 { Opt_acdirmin, "acdirmin=%u" }, 151 { Opt_acdirmin, "acdirmin=%s" },
152 { Opt_acdirmax, "acdirmax=%u" }, 152 { Opt_acdirmax, "acdirmax=%s" },
153 { Opt_actimeo, "actimeo=%u" }, 153 { Opt_actimeo, "actimeo=%s" },
154 { Opt_namelen, "namlen=%u" }, 154 { Opt_namelen, "namlen=%s" },
155 { Opt_mountport, "mountport=%u" }, 155 { Opt_mountport, "mountport=%s" },
156 { Opt_mountvers, "mountvers=%u" }, 156 { Opt_mountvers, "mountvers=%s" },
157 { Opt_nfsvers, "nfsvers=%u" }, 157 { Opt_nfsvers, "nfsvers=%s" },
158 { Opt_nfsvers, "vers=%u" }, 158 { Opt_nfsvers, "vers=%s" },
159 { Opt_minorversion, "minorversion=%u" }, 159 { Opt_minorversion, "minorversion=%u" },
160 160
161 { Opt_sec, "sec=%s" }, 161 { Opt_sec, "sec=%s" },
@@ -516,7 +516,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
516 const char *nostr; 516 const char *nostr;
517 } nfs_info[] = { 517 } nfs_info[] = {
518 { NFS_MOUNT_SOFT, ",soft", ",hard" }, 518 { NFS_MOUNT_SOFT, ",soft", ",hard" },
519 { NFS_MOUNT_INTR, ",intr", ",nointr" },
520 { NFS_MOUNT_POSIX, ",posix", "" }, 519 { NFS_MOUNT_POSIX, ",posix", "" },
521 { NFS_MOUNT_NOCTO, ",nocto", "" }, 520 { NFS_MOUNT_NOCTO, ",nocto", "" },
522 { NFS_MOUNT_NOAC, ",noac", "" }, 521 { NFS_MOUNT_NOAC, ",noac", "" },
@@ -945,11 +944,6 @@ static int nfs_parse_security_flavors(char *value,
945 return 1; 944 return 1;
946} 945}
947 946
948static void nfs_parse_invalid_value(const char *option)
949{
950 dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option);
951}
952
953/* 947/*
954 * Error-check and convert a string of mount options from user space into 948 * Error-check and convert a string of mount options from user space into
955 * a data structure. The whole mount string is processed; bad options are 949 * a data structure. The whole mount string is processed; bad options are
@@ -960,7 +954,7 @@ static int nfs_parse_mount_options(char *raw,
960 struct nfs_parsed_mount_data *mnt) 954 struct nfs_parsed_mount_data *mnt)
961{ 955{
962 char *p, *string, *secdata; 956 char *p, *string, *secdata;
963 int rc, sloppy = 0, errors = 0; 957 int rc, sloppy = 0, invalid_option = 0;
964 958
965 if (!raw) { 959 if (!raw) {
966 dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); 960 dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
@@ -984,7 +978,9 @@ static int nfs_parse_mount_options(char *raw,
984 978
985 while ((p = strsep(&raw, ",")) != NULL) { 979 while ((p = strsep(&raw, ",")) != NULL) {
986 substring_t args[MAX_OPT_ARGS]; 980 substring_t args[MAX_OPT_ARGS];
987 int option, token; 981 unsigned long option;
982 int int_option;
983 int token;
988 984
989 if (!*p) 985 if (!*p)
990 continue; 986 continue;
@@ -1093,114 +1089,156 @@ static int nfs_parse_mount_options(char *raw,
1093 * options that take numeric values 1089 * options that take numeric values
1094 */ 1090 */
1095 case Opt_port: 1091 case Opt_port:
1096 if (match_int(args, &option) || 1092 string = match_strdup(args);
1097 option < 0 || option > USHORT_MAX) { 1093 if (string == NULL)
1098 errors++; 1094 goto out_nomem;
1099 nfs_parse_invalid_value("port"); 1095 rc = strict_strtoul(string, 10, &option);
1100 } else 1096 kfree(string);
1101 mnt->nfs_server.port = option; 1097 if (rc != 0 || option > USHORT_MAX)
1098 goto out_invalid_value;
1099 mnt->nfs_server.port = option;
1102 break; 1100 break;
1103 case Opt_rsize: 1101 case Opt_rsize:
1104 if (match_int(args, &option) || option < 0) { 1102 string = match_strdup(args);
1105 errors++; 1103 if (string == NULL)
1106 nfs_parse_invalid_value("rsize"); 1104 goto out_nomem;
1107 } else 1105 rc = strict_strtoul(string, 10, &option);
1108 mnt->rsize = option; 1106 kfree(string);
1107 if (rc != 0)
1108 goto out_invalid_value;
1109 mnt->rsize = option;
1109 break; 1110 break;
1110 case Opt_wsize: 1111 case Opt_wsize:
1111 if (match_int(args, &option) || option < 0) { 1112 string = match_strdup(args);
1112 errors++; 1113 if (string == NULL)
1113 nfs_parse_invalid_value("wsize"); 1114 goto out_nomem;
1114 } else 1115 rc = strict_strtoul(string, 10, &option);
1115 mnt->wsize = option; 1116 kfree(string);
1117 if (rc != 0)
1118 goto out_invalid_value;
1119 mnt->wsize = option;
1116 break; 1120 break;
1117 case Opt_bsize: 1121 case Opt_bsize:
1118 if (match_int(args, &option) || option < 0) { 1122 string = match_strdup(args);
1119 errors++; 1123 if (string == NULL)
1120 nfs_parse_invalid_value("bsize"); 1124 goto out_nomem;
1121 } else 1125 rc = strict_strtoul(string, 10, &option);
1122 mnt->bsize = option; 1126 kfree(string);
1127 if (rc != 0)
1128 goto out_invalid_value;
1129 mnt->bsize = option;
1123 break; 1130 break;
1124 case Opt_timeo: 1131 case Opt_timeo:
1125 if (match_int(args, &option) || option <= 0) { 1132 string = match_strdup(args);
1126 errors++; 1133 if (string == NULL)
1127 nfs_parse_invalid_value("timeo"); 1134 goto out_nomem;
1128 } else 1135 rc = strict_strtoul(string, 10, &option);
1129 mnt->timeo = option; 1136 kfree(string);
1137 if (rc != 0 || option == 0)
1138 goto out_invalid_value;
1139 mnt->timeo = option;
1130 break; 1140 break;
1131 case Opt_retrans: 1141 case Opt_retrans:
1132 if (match_int(args, &option) || option <= 0) { 1142 string = match_strdup(args);
1133 errors++; 1143 if (string == NULL)
1134 nfs_parse_invalid_value("retrans"); 1144 goto out_nomem;
1135 } else 1145 rc = strict_strtoul(string, 10, &option);
1136 mnt->retrans = option; 1146 kfree(string);
1147 if (rc != 0 || option == 0)
1148 goto out_invalid_value;
1149 mnt->retrans = option;
1137 break; 1150 break;
1138 case Opt_acregmin: 1151 case Opt_acregmin:
1139 if (match_int(args, &option) || option < 0) { 1152 string = match_strdup(args);
1140 errors++; 1153 if (string == NULL)
1141 nfs_parse_invalid_value("acregmin"); 1154 goto out_nomem;
1142 } else 1155 rc = strict_strtoul(string, 10, &option);
1143 mnt->acregmin = option; 1156 kfree(string);
1157 if (rc != 0)
1158 goto out_invalid_value;
1159 mnt->acregmin = option;
1144 break; 1160 break;
1145 case Opt_acregmax: 1161 case Opt_acregmax:
1146 if (match_int(args, &option) || option < 0) { 1162 string = match_strdup(args);
1147 errors++; 1163 if (string == NULL)
1148 nfs_parse_invalid_value("acregmax"); 1164 goto out_nomem;
1149 } else 1165 rc = strict_strtoul(string, 10, &option);
1150 mnt->acregmax = option; 1166 kfree(string);
1167 if (rc != 0)
1168 goto out_invalid_value;
1169 mnt->acregmax = option;
1151 break; 1170 break;
1152 case Opt_acdirmin: 1171 case Opt_acdirmin:
1153 if (match_int(args, &option) || option < 0) { 1172 string = match_strdup(args);
1154 errors++; 1173 if (string == NULL)
1155 nfs_parse_invalid_value("acdirmin"); 1174 goto out_nomem;
1156 } else 1175 rc = strict_strtoul(string, 10, &option);
1157 mnt->acdirmin = option; 1176 kfree(string);
1177 if (rc != 0)
1178 goto out_invalid_value;
1179 mnt->acdirmin = option;
1158 break; 1180 break;
1159 case Opt_acdirmax: 1181 case Opt_acdirmax:
1160 if (match_int(args, &option) || option < 0) { 1182 string = match_strdup(args);
1161 errors++; 1183 if (string == NULL)
1162 nfs_parse_invalid_value("acdirmax"); 1184 goto out_nomem;
1163 } else 1185 rc = strict_strtoul(string, 10, &option);
1164 mnt->acdirmax = option; 1186 kfree(string);
1187 if (rc != 0)
1188 goto out_invalid_value;
1189 mnt->acdirmax = option;
1165 break; 1190 break;
1166 case Opt_actimeo: 1191 case Opt_actimeo:
1167 if (match_int(args, &option) || option < 0) { 1192 string = match_strdup(args);
1168 errors++; 1193 if (string == NULL)
1169 nfs_parse_invalid_value("actimeo"); 1194 goto out_nomem;
1170 } else 1195 rc = strict_strtoul(string, 10, &option);
1171 mnt->acregmin = mnt->acregmax = 1196 kfree(string);
1172 mnt->acdirmin = mnt->acdirmax = option; 1197 if (rc != 0)
1198 goto out_invalid_value;
1199 mnt->acregmin = mnt->acregmax =
1200 mnt->acdirmin = mnt->acdirmax = option;
1173 break; 1201 break;
1174 case Opt_namelen: 1202 case Opt_namelen:
1175 if (match_int(args, &option) || option < 0) { 1203 string = match_strdup(args);
1176 errors++; 1204 if (string == NULL)
1177 nfs_parse_invalid_value("namlen"); 1205 goto out_nomem;
1178 } else 1206 rc = strict_strtoul(string, 10, &option);
1179 mnt->namlen = option; 1207 kfree(string);
1208 if (rc != 0)
1209 goto out_invalid_value;
1210 mnt->namlen = option;
1180 break; 1211 break;
1181 case Opt_mountport: 1212 case Opt_mountport:
1182 if (match_int(args, &option) || 1213 string = match_strdup(args);
1183 option < 0 || option > USHORT_MAX) { 1214 if (string == NULL)
1184 errors++; 1215 goto out_nomem;
1185 nfs_parse_invalid_value("mountport"); 1216 rc = strict_strtoul(string, 10, &option);
1186 } else 1217 kfree(string);
1187 mnt->mount_server.port = option; 1218 if (rc != 0 || option > USHORT_MAX)
1219 goto out_invalid_value;
1220 mnt->mount_server.port = option;
1188 break; 1221 break;
1189 case Opt_mountvers: 1222 case Opt_mountvers:
1190 if (match_int(args, &option) || 1223 string = match_strdup(args);
1224 if (string == NULL)
1225 goto out_nomem;
1226 rc = strict_strtoul(string, 10, &option);
1227 kfree(string);
1228 if (rc != 0 ||
1191 option < NFS_MNT_VERSION || 1229 option < NFS_MNT_VERSION ||
1192 option > NFS_MNT3_VERSION) { 1230 option > NFS_MNT3_VERSION)
1193 errors++; 1231 goto out_invalid_value;
1194 nfs_parse_invalid_value("mountvers"); 1232 mnt->mount_server.version = option;
1195 } else
1196 mnt->mount_server.version = option;
1197 break; 1233 break;
1198 case Opt_nfsvers: 1234 case Opt_nfsvers:
1199 if (match_int(args, &option)) { 1235 string = match_strdup(args);
1200 errors++; 1236 if (string == NULL)
1201 nfs_parse_invalid_value("nfsvers"); 1237 goto out_nomem;
1202 break; 1238 rc = strict_strtoul(string, 10, &option);
1203 } 1239 kfree(string);
1240 if (rc != 0)
1241 goto out_invalid_value;
1204 switch (option) { 1242 switch (option) {
1205 case NFS2_VERSION: 1243 case NFS2_VERSION:
1206 mnt->flags &= ~NFS_MOUNT_VER3; 1244 mnt->flags &= ~NFS_MOUNT_VER3;
@@ -1209,16 +1247,15 @@ static int nfs_parse_mount_options(char *raw,
1209 mnt->flags |= NFS_MOUNT_VER3; 1247 mnt->flags |= NFS_MOUNT_VER3;
1210 break; 1248 break;
1211 default: 1249 default:
1212 errors++; 1250 goto out_invalid_value;
1213 nfs_parse_invalid_value("nfsvers");
1214 } 1251 }
1215 break; 1252 break;
1216 case Opt_minorversion: 1253 case Opt_minorversion:
1217 if (match_int(args, &option)) 1254 if (match_int(args, &int_option))
1218 return 0; 1255 return 0;
1219 if (option < 0 || option > NFS4_MAX_MINOR_VERSION) 1256 if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION)
1220 return 0; 1257 return 0;
1221 mnt->minorversion = option; 1258 mnt->minorversion = int_option;
1222 break; 1259 break;
1223 1260
1224 /* 1261 /*
@@ -1231,9 +1268,9 @@ static int nfs_parse_mount_options(char *raw,
1231 rc = nfs_parse_security_flavors(string, mnt); 1268 rc = nfs_parse_security_flavors(string, mnt);
1232 kfree(string); 1269 kfree(string);
1233 if (!rc) { 1270 if (!rc) {
1234 errors++;
1235 dfprintk(MOUNT, "NFS: unrecognized " 1271 dfprintk(MOUNT, "NFS: unrecognized "
1236 "security flavor\n"); 1272 "security flavor\n");
1273 return 0;
1237 } 1274 }
1238 break; 1275 break;
1239 case Opt_proto: 1276 case Opt_proto:
@@ -1247,23 +1284,25 @@ static int nfs_parse_mount_options(char *raw,
1247 case Opt_xprt_udp: 1284 case Opt_xprt_udp:
1248 mnt->flags &= ~NFS_MOUNT_TCP; 1285 mnt->flags &= ~NFS_MOUNT_TCP;
1249 mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; 1286 mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
1287 kfree(string);
1250 break; 1288 break;
1251 case Opt_xprt_tcp: 1289 case Opt_xprt_tcp:
1252 mnt->flags |= NFS_MOUNT_TCP; 1290 mnt->flags |= NFS_MOUNT_TCP;
1253 mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; 1291 mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
1292 kfree(string);
1254 break; 1293 break;
1255 case Opt_xprt_rdma: 1294 case Opt_xprt_rdma:
1256 /* vector side protocols to TCP */ 1295 /* vector side protocols to TCP */
1257 mnt->flags |= NFS_MOUNT_TCP; 1296 mnt->flags |= NFS_MOUNT_TCP;
1258 mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; 1297 mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
1259 xprt_load_transport(string); 1298 xprt_load_transport(string);
1299 kfree(string);
1260 break; 1300 break;
1261 default: 1301 default:
1262 errors++;
1263 dfprintk(MOUNT, "NFS: unrecognized " 1302 dfprintk(MOUNT, "NFS: unrecognized "
1264 "transport protocol\n"); 1303 "transport protocol\n");
1304 return 0;
1265 } 1305 }
1266 kfree(string);
1267 break; 1306 break;
1268 case Opt_mountproto: 1307 case Opt_mountproto:
1269 string = match_strdup(args); 1308 string = match_strdup(args);
@@ -1282,9 +1321,9 @@ static int nfs_parse_mount_options(char *raw,
1282 break; 1321 break;
1283 case Opt_xprt_rdma: /* not used for side protocols */ 1322 case Opt_xprt_rdma: /* not used for side protocols */
1284 default: 1323 default:
1285 errors++;
1286 dfprintk(MOUNT, "NFS: unrecognized " 1324 dfprintk(MOUNT, "NFS: unrecognized "
1287 "transport protocol\n"); 1325 "transport protocol\n");
1326 return 0;
1288 } 1327 }
1289 break; 1328 break;
1290 case Opt_addr: 1329 case Opt_addr:
@@ -1340,9 +1379,9 @@ static int nfs_parse_mount_options(char *raw,
1340 mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; 1379 mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
1341 break; 1380 break;
1342 default: 1381 default:
1343 errors++;
1344 dfprintk(MOUNT, "NFS: invalid " 1382 dfprintk(MOUNT, "NFS: invalid "
1345 "lookupcache argument\n"); 1383 "lookupcache argument\n");
1384 return 0;
1346 }; 1385 };
1347 break; 1386 break;
1348 1387
@@ -1360,20 +1399,20 @@ static int nfs_parse_mount_options(char *raw,
1360 break; 1399 break;
1361 1400
1362 default: 1401 default:
1363 errors++; 1402 invalid_option = 1;
1364 dfprintk(MOUNT, "NFS: unrecognized mount option " 1403 dfprintk(MOUNT, "NFS: unrecognized mount option "
1365 "'%s'\n", p); 1404 "'%s'\n", p);
1366 } 1405 }
1367 } 1406 }
1368 1407
1369 if (errors > 0) { 1408 if (!sloppy && invalid_option)
1370 dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", 1409 return 0;
1371 errors, (errors == 1 ? "" : "s")); 1410
1372 if (!sloppy)
1373 return 0;
1374 }
1375 return 1; 1411 return 1;
1376 1412
1413out_invalid_value:
1414 printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p);
1415 return 0;
1377out_nomem: 1416out_nomem:
1378 printk(KERN_INFO "NFS: not enough memory to parse option\n"); 1417 printk(KERN_INFO "NFS: not enough memory to parse option\n");
1379 return 0; 1418 return 0;
@@ -1390,6 +1429,7 @@ out_security_failure:
1390static int nfs_try_mount(struct nfs_parsed_mount_data *args, 1429static int nfs_try_mount(struct nfs_parsed_mount_data *args,
1391 struct nfs_fh *root_fh) 1430 struct nfs_fh *root_fh)
1392{ 1431{
1432 unsigned int auth_flavor_len = 0;
1393 struct nfs_mount_request request = { 1433 struct nfs_mount_request request = {
1394 .sap = (struct sockaddr *) 1434 .sap = (struct sockaddr *)
1395 &args->mount_server.address, 1435 &args->mount_server.address,
@@ -1397,6 +1437,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
1397 .protocol = args->mount_server.protocol, 1437 .protocol = args->mount_server.protocol,
1398 .fh = root_fh, 1438 .fh = root_fh,
1399 .noresvport = args->flags & NFS_MOUNT_NORESVPORT, 1439 .noresvport = args->flags & NFS_MOUNT_NORESVPORT,
1440 .auth_flav_len = &auth_flavor_len,
1400 }; 1441 };
1401 int status; 1442 int status;
1402 1443
@@ -2249,6 +2290,11 @@ static void nfs4_fill_super(struct super_block *sb)
2249 nfs_initialise_sb(sb); 2290 nfs_initialise_sb(sb);
2250} 2291}
2251 2292
2293static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
2294{
2295 args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3);
2296}
2297
2252/* 2298/*
2253 * Validate NFSv4 mount options 2299 * Validate NFSv4 mount options
2254 */ 2300 */
@@ -2346,6 +2392,8 @@ static int nfs4_validate_mount_data(void *options,
2346 2392
2347 nfs_validate_transport_protocol(args); 2393 nfs_validate_transport_protocol(args);
2348 2394
2395 nfs4_validate_mount_flags(args);
2396
2349 if (args->auth_flavor_len > 1) 2397 if (args->auth_flavor_len > 1)
2350 goto out_inval_auth; 2398 goto out_inval_auth;
2351 2399