Commit 35f7a14fc1180164d6358a5885031fc187ef1bfa
1 parent
1c327d962f
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
nfsd4: fix minorversion support interface
You can turn on or off support for minorversions using e.g. echo "-4.2" >/proc/fs/nfsd/versions However, the current implementation is a little wonky. For example, the above will turn off 4.2 support, but it will also turn *on* 4.1 support. This didn't matter as long as we only had 2 minorversions, which was true till very recently. And do a little cleanup here. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Showing 3 changed files with 8 additions and 8 deletions Inline Diff
fs/nfsd/nfs4proc.c
1 | /* | 1 | /* |
2 | * Server-side procedures for NFSv4. | 2 | * Server-side procedures for NFSv4. |
3 | * | 3 | * |
4 | * Copyright (c) 2002 The Regents of the University of Michigan. | 4 | * Copyright (c) 2002 The Regents of the University of Michigan. |
5 | * All rights reserved. | 5 | * All rights reserved. |
6 | * | 6 | * |
7 | * Kendrick Smith <kmsmith@umich.edu> | 7 | * Kendrick Smith <kmsmith@umich.edu> |
8 | * Andy Adamson <andros@umich.edu> | 8 | * Andy Adamson <andros@umich.edu> |
9 | * | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | 12 | * are met: |
13 | * | 13 | * |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | 18 | * documentation and/or other materials provided with the distribution. |
19 | * 3. Neither the name of the University nor the names of its | 19 | * 3. Neither the name of the University nor the names of its |
20 | * contributors may be used to endorse or promote products derived | 20 | * contributors may be used to endorse or promote products derived |
21 | * from this software without specific prior written permission. | 21 | * from this software without specific prior written permission. |
22 | * | 22 | * |
23 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | 23 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
24 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 24 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
26 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 26 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | 29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
30 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 30 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 | */ | 34 | */ |
35 | #include <linux/file.h> | 35 | #include <linux/file.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | 37 | ||
38 | #include "idmap.h" | 38 | #include "idmap.h" |
39 | #include "cache.h" | 39 | #include "cache.h" |
40 | #include "xdr4.h" | 40 | #include "xdr4.h" |
41 | #include "vfs.h" | 41 | #include "vfs.h" |
42 | #include "current_stateid.h" | 42 | #include "current_stateid.h" |
43 | #include "netns.h" | 43 | #include "netns.h" |
44 | 44 | ||
45 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | 45 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL |
46 | #include <linux/security.h> | 46 | #include <linux/security.h> |
47 | 47 | ||
48 | static inline void | 48 | static inline void |
49 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) | 49 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) |
50 | { | 50 | { |
51 | struct inode *inode = resfh->fh_dentry->d_inode; | 51 | struct inode *inode = resfh->fh_dentry->d_inode; |
52 | int status; | 52 | int status; |
53 | 53 | ||
54 | mutex_lock(&inode->i_mutex); | 54 | mutex_lock(&inode->i_mutex); |
55 | status = security_inode_setsecctx(resfh->fh_dentry, | 55 | status = security_inode_setsecctx(resfh->fh_dentry, |
56 | label->data, label->len); | 56 | label->data, label->len); |
57 | mutex_unlock(&inode->i_mutex); | 57 | mutex_unlock(&inode->i_mutex); |
58 | 58 | ||
59 | if (status) | 59 | if (status) |
60 | /* | 60 | /* |
61 | * XXX: We should really fail the whole open, but we may | 61 | * XXX: We should really fail the whole open, but we may |
62 | * already have created a new file, so it may be too | 62 | * already have created a new file, so it may be too |
63 | * late. For now this seems the least of evils: | 63 | * late. For now this seems the least of evils: |
64 | */ | 64 | */ |
65 | bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; | 65 | bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; |
66 | 66 | ||
67 | return; | 67 | return; |
68 | } | 68 | } |
69 | #else | 69 | #else |
70 | static inline void | 70 | static inline void |
71 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) | 71 | nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) |
72 | { } | 72 | { } |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 75 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
76 | 76 | ||
77 | static u32 nfsd_attrmask[] = { | 77 | static u32 nfsd_attrmask[] = { |
78 | NFSD_WRITEABLE_ATTRS_WORD0, | 78 | NFSD_WRITEABLE_ATTRS_WORD0, |
79 | NFSD_WRITEABLE_ATTRS_WORD1, | 79 | NFSD_WRITEABLE_ATTRS_WORD1, |
80 | NFSD_WRITEABLE_ATTRS_WORD2 | 80 | NFSD_WRITEABLE_ATTRS_WORD2 |
81 | }; | 81 | }; |
82 | 82 | ||
83 | static u32 nfsd41_ex_attrmask[] = { | 83 | static u32 nfsd41_ex_attrmask[] = { |
84 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | 84 | NFSD_SUPPATTR_EXCLCREAT_WORD0, |
85 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | 85 | NFSD_SUPPATTR_EXCLCREAT_WORD1, |
86 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | 86 | NFSD_SUPPATTR_EXCLCREAT_WORD2 |
87 | }; | 87 | }; |
88 | 88 | ||
89 | static __be32 | 89 | static __be32 |
90 | check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 90 | check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
91 | u32 *bmval, u32 *writable) | 91 | u32 *bmval, u32 *writable) |
92 | { | 92 | { |
93 | struct dentry *dentry = cstate->current_fh.fh_dentry; | 93 | struct dentry *dentry = cstate->current_fh.fh_dentry; |
94 | 94 | ||
95 | /* | 95 | /* |
96 | * Check about attributes are supported by the NFSv4 server or not. | 96 | * Check about attributes are supported by the NFSv4 server or not. |
97 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP. | 97 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP. |
98 | */ | 98 | */ |
99 | if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) || | 99 | if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) || |
100 | (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) || | 100 | (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) || |
101 | (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | 101 | (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) |
102 | return nfserr_attrnotsupp; | 102 | return nfserr_attrnotsupp; |
103 | 103 | ||
104 | /* | 104 | /* |
105 | * Check FATTR4_WORD0_ACL can be supported | 105 | * Check FATTR4_WORD0_ACL can be supported |
106 | * in current environment or not. | 106 | * in current environment or not. |
107 | */ | 107 | */ |
108 | if (bmval[0] & FATTR4_WORD0_ACL) { | 108 | if (bmval[0] & FATTR4_WORD0_ACL) { |
109 | if (!IS_POSIXACL(dentry->d_inode)) | 109 | if (!IS_POSIXACL(dentry->d_inode)) |
110 | return nfserr_attrnotsupp; | 110 | return nfserr_attrnotsupp; |
111 | } | 111 | } |
112 | 112 | ||
113 | /* | 113 | /* |
114 | * According to spec, read-only attributes return ERR_INVAL. | 114 | * According to spec, read-only attributes return ERR_INVAL. |
115 | */ | 115 | */ |
116 | if (writable) { | 116 | if (writable) { |
117 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | 117 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || |
118 | (bmval[2] & ~writable[2])) | 118 | (bmval[2] & ~writable[2])) |
119 | return nfserr_inval; | 119 | return nfserr_inval; |
120 | } | 120 | } |
121 | 121 | ||
122 | return nfs_ok; | 122 | return nfs_ok; |
123 | } | 123 | } |
124 | 124 | ||
125 | static __be32 | 125 | static __be32 |
126 | nfsd4_check_open_attributes(struct svc_rqst *rqstp, | 126 | nfsd4_check_open_attributes(struct svc_rqst *rqstp, |
127 | struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | 127 | struct nfsd4_compound_state *cstate, struct nfsd4_open *open) |
128 | { | 128 | { |
129 | __be32 status = nfs_ok; | 129 | __be32 status = nfs_ok; |
130 | 130 | ||
131 | if (open->op_create == NFS4_OPEN_CREATE) { | 131 | if (open->op_create == NFS4_OPEN_CREATE) { |
132 | if (open->op_createmode == NFS4_CREATE_UNCHECKED | 132 | if (open->op_createmode == NFS4_CREATE_UNCHECKED |
133 | || open->op_createmode == NFS4_CREATE_GUARDED) | 133 | || open->op_createmode == NFS4_CREATE_GUARDED) |
134 | status = check_attr_support(rqstp, cstate, | 134 | status = check_attr_support(rqstp, cstate, |
135 | open->op_bmval, nfsd_attrmask); | 135 | open->op_bmval, nfsd_attrmask); |
136 | else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1) | 136 | else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1) |
137 | status = check_attr_support(rqstp, cstate, | 137 | status = check_attr_support(rqstp, cstate, |
138 | open->op_bmval, nfsd41_ex_attrmask); | 138 | open->op_bmval, nfsd41_ex_attrmask); |
139 | } | 139 | } |
140 | 140 | ||
141 | return status; | 141 | return status; |
142 | } | 142 | } |
143 | 143 | ||
144 | static int | 144 | static int |
145 | is_create_with_attrs(struct nfsd4_open *open) | 145 | is_create_with_attrs(struct nfsd4_open *open) |
146 | { | 146 | { |
147 | return open->op_create == NFS4_OPEN_CREATE | 147 | return open->op_create == NFS4_OPEN_CREATE |
148 | && (open->op_createmode == NFS4_CREATE_UNCHECKED | 148 | && (open->op_createmode == NFS4_CREATE_UNCHECKED |
149 | || open->op_createmode == NFS4_CREATE_GUARDED | 149 | || open->op_createmode == NFS4_CREATE_GUARDED |
150 | || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1); | 150 | || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1); |
151 | } | 151 | } |
152 | 152 | ||
153 | /* | 153 | /* |
154 | * if error occurs when setting the acl, just clear the acl bit | 154 | * if error occurs when setting the acl, just clear the acl bit |
155 | * in the returned attr bitmap. | 155 | * in the returned attr bitmap. |
156 | */ | 156 | */ |
157 | static void | 157 | static void |
158 | do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | 158 | do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, |
159 | struct nfs4_acl *acl, u32 *bmval) | 159 | struct nfs4_acl *acl, u32 *bmval) |
160 | { | 160 | { |
161 | __be32 status; | 161 | __be32 status; |
162 | 162 | ||
163 | status = nfsd4_set_nfs4_acl(rqstp, fhp, acl); | 163 | status = nfsd4_set_nfs4_acl(rqstp, fhp, acl); |
164 | if (status) | 164 | if (status) |
165 | /* | 165 | /* |
166 | * We should probably fail the whole open at this point, | 166 | * We should probably fail the whole open at this point, |
167 | * but we've already created the file, so it's too late; | 167 | * but we've already created the file, so it's too late; |
168 | * So this seems the least of evils: | 168 | * So this seems the least of evils: |
169 | */ | 169 | */ |
170 | bmval[0] &= ~FATTR4_WORD0_ACL; | 170 | bmval[0] &= ~FATTR4_WORD0_ACL; |
171 | } | 171 | } |
172 | 172 | ||
173 | static inline void | 173 | static inline void |
174 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) | 174 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) |
175 | { | 175 | { |
176 | fh_put(dst); | 176 | fh_put(dst); |
177 | dget(src->fh_dentry); | 177 | dget(src->fh_dentry); |
178 | if (src->fh_export) | 178 | if (src->fh_export) |
179 | cache_get(&src->fh_export->h); | 179 | cache_get(&src->fh_export->h); |
180 | *dst = *src; | 180 | *dst = *src; |
181 | } | 181 | } |
182 | 182 | ||
183 | static __be32 | 183 | static __be32 |
184 | do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode) | 184 | do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode) |
185 | { | 185 | { |
186 | __be32 status; | 186 | __be32 status; |
187 | 187 | ||
188 | if (open->op_truncate && | 188 | if (open->op_truncate && |
189 | !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) | 189 | !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) |
190 | return nfserr_inval; | 190 | return nfserr_inval; |
191 | 191 | ||
192 | accmode |= NFSD_MAY_READ_IF_EXEC; | 192 | accmode |= NFSD_MAY_READ_IF_EXEC; |
193 | 193 | ||
194 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) | 194 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) |
195 | accmode |= NFSD_MAY_READ; | 195 | accmode |= NFSD_MAY_READ; |
196 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 196 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
197 | accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC); | 197 | accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC); |
198 | if (open->op_share_deny & NFS4_SHARE_DENY_READ) | 198 | if (open->op_share_deny & NFS4_SHARE_DENY_READ) |
199 | accmode |= NFSD_MAY_WRITE; | 199 | accmode |= NFSD_MAY_WRITE; |
200 | 200 | ||
201 | status = fh_verify(rqstp, current_fh, S_IFREG, accmode); | 201 | status = fh_verify(rqstp, current_fh, S_IFREG, accmode); |
202 | 202 | ||
203 | return status; | 203 | return status; |
204 | } | 204 | } |
205 | 205 | ||
206 | static __be32 nfsd_check_obj_isreg(struct svc_fh *fh) | 206 | static __be32 nfsd_check_obj_isreg(struct svc_fh *fh) |
207 | { | 207 | { |
208 | umode_t mode = fh->fh_dentry->d_inode->i_mode; | 208 | umode_t mode = fh->fh_dentry->d_inode->i_mode; |
209 | 209 | ||
210 | if (S_ISREG(mode)) | 210 | if (S_ISREG(mode)) |
211 | return nfs_ok; | 211 | return nfs_ok; |
212 | if (S_ISDIR(mode)) | 212 | if (S_ISDIR(mode)) |
213 | return nfserr_isdir; | 213 | return nfserr_isdir; |
214 | /* | 214 | /* |
215 | * Using err_symlink as our catch-all case may look odd; but | 215 | * Using err_symlink as our catch-all case may look odd; but |
216 | * there's no other obvious error for this case in 4.0, and we | 216 | * there's no other obvious error for this case in 4.0, and we |
217 | * happen to know that it will cause the linux v4 client to do | 217 | * happen to know that it will cause the linux v4 client to do |
218 | * the right thing on attempts to open something other than a | 218 | * the right thing on attempts to open something other than a |
219 | * regular file. | 219 | * regular file. |
220 | */ | 220 | */ |
221 | return nfserr_symlink; | 221 | return nfserr_symlink; |
222 | } | 222 | } |
223 | 223 | ||
224 | static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh *resfh) | 224 | static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh *resfh) |
225 | { | 225 | { |
226 | if (nfsd4_has_session(cstate)) | 226 | if (nfsd4_has_session(cstate)) |
227 | return; | 227 | return; |
228 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, | 228 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
229 | &resfh->fh_handle); | 229 | &resfh->fh_handle); |
230 | } | 230 | } |
231 | 231 | ||
232 | static __be32 | 232 | static __be32 |
233 | do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | 233 | do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open) |
234 | { | 234 | { |
235 | struct svc_fh *current_fh = &cstate->current_fh; | 235 | struct svc_fh *current_fh = &cstate->current_fh; |
236 | struct svc_fh *resfh; | 236 | struct svc_fh *resfh; |
237 | int accmode; | 237 | int accmode; |
238 | __be32 status; | 238 | __be32 status; |
239 | 239 | ||
240 | resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); | 240 | resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); |
241 | if (!resfh) | 241 | if (!resfh) |
242 | return nfserr_jukebox; | 242 | return nfserr_jukebox; |
243 | fh_init(resfh, NFS4_FHSIZE); | 243 | fh_init(resfh, NFS4_FHSIZE); |
244 | open->op_truncate = 0; | 244 | open->op_truncate = 0; |
245 | 245 | ||
246 | if (open->op_create) { | 246 | if (open->op_create) { |
247 | /* FIXME: check session persistence and pnfs flags. | 247 | /* FIXME: check session persistence and pnfs flags. |
248 | * The nfsv4.1 spec requires the following semantics: | 248 | * The nfsv4.1 spec requires the following semantics: |
249 | * | 249 | * |
250 | * Persistent | pNFS | Server REQUIRED | Client Allowed | 250 | * Persistent | pNFS | Server REQUIRED | Client Allowed |
251 | * Reply Cache | server | | | 251 | * Reply Cache | server | | |
252 | * -------------+--------+-----------------+-------------------- | 252 | * -------------+--------+-----------------+-------------------- |
253 | * no | no | EXCLUSIVE4_1 | EXCLUSIVE4_1 | 253 | * no | no | EXCLUSIVE4_1 | EXCLUSIVE4_1 |
254 | * | | | (SHOULD) | 254 | * | | | (SHOULD) |
255 | * | | and EXCLUSIVE4 | or EXCLUSIVE4 | 255 | * | | and EXCLUSIVE4 | or EXCLUSIVE4 |
256 | * | | | (SHOULD NOT) | 256 | * | | | (SHOULD NOT) |
257 | * no | yes | EXCLUSIVE4_1 | EXCLUSIVE4_1 | 257 | * no | yes | EXCLUSIVE4_1 | EXCLUSIVE4_1 |
258 | * yes | no | GUARDED4 | GUARDED4 | 258 | * yes | no | GUARDED4 | GUARDED4 |
259 | * yes | yes | GUARDED4 | GUARDED4 | 259 | * yes | yes | GUARDED4 | GUARDED4 |
260 | */ | 260 | */ |
261 | 261 | ||
262 | /* | 262 | /* |
263 | * Note: create modes (UNCHECKED,GUARDED...) are the same | 263 | * Note: create modes (UNCHECKED,GUARDED...) are the same |
264 | * in NFSv4 as in v3 except EXCLUSIVE4_1. | 264 | * in NFSv4 as in v3 except EXCLUSIVE4_1. |
265 | */ | 265 | */ |
266 | status = do_nfsd_create(rqstp, current_fh, open->op_fname.data, | 266 | status = do_nfsd_create(rqstp, current_fh, open->op_fname.data, |
267 | open->op_fname.len, &open->op_iattr, | 267 | open->op_fname.len, &open->op_iattr, |
268 | resfh, open->op_createmode, | 268 | resfh, open->op_createmode, |
269 | (u32 *)open->op_verf.data, | 269 | (u32 *)open->op_verf.data, |
270 | &open->op_truncate, &open->op_created); | 270 | &open->op_truncate, &open->op_created); |
271 | 271 | ||
272 | if (!status && open->op_label.len) | 272 | if (!status && open->op_label.len) |
273 | nfsd4_security_inode_setsecctx(resfh, &open->op_label, open->op_bmval); | 273 | nfsd4_security_inode_setsecctx(resfh, &open->op_label, open->op_bmval); |
274 | 274 | ||
275 | /* | 275 | /* |
276 | * Following rfc 3530 14.2.16, use the returned bitmask | 276 | * Following rfc 3530 14.2.16, use the returned bitmask |
277 | * to indicate which attributes we used to store the | 277 | * to indicate which attributes we used to store the |
278 | * verifier: | 278 | * verifier: |
279 | */ | 279 | */ |
280 | if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0) | 280 | if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0) |
281 | open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS | | 281 | open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS | |
282 | FATTR4_WORD1_TIME_MODIFY); | 282 | FATTR4_WORD1_TIME_MODIFY); |
283 | } else { | 283 | } else { |
284 | status = nfsd_lookup(rqstp, current_fh, | 284 | status = nfsd_lookup(rqstp, current_fh, |
285 | open->op_fname.data, open->op_fname.len, resfh); | 285 | open->op_fname.data, open->op_fname.len, resfh); |
286 | fh_unlock(current_fh); | 286 | fh_unlock(current_fh); |
287 | } | 287 | } |
288 | if (status) | 288 | if (status) |
289 | goto out; | 289 | goto out; |
290 | status = nfsd_check_obj_isreg(resfh); | 290 | status = nfsd_check_obj_isreg(resfh); |
291 | if (status) | 291 | if (status) |
292 | goto out; | 292 | goto out; |
293 | 293 | ||
294 | if (is_create_with_attrs(open) && open->op_acl != NULL) | 294 | if (is_create_with_attrs(open) && open->op_acl != NULL) |
295 | do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval); | 295 | do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval); |
296 | 296 | ||
297 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); | 297 | nfsd4_set_open_owner_reply_cache(cstate, open, resfh); |
298 | accmode = NFSD_MAY_NOP; | 298 | accmode = NFSD_MAY_NOP; |
299 | if (open->op_created || | 299 | if (open->op_created || |
300 | open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | 300 | open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) |
301 | accmode |= NFSD_MAY_OWNER_OVERRIDE; | 301 | accmode |= NFSD_MAY_OWNER_OVERRIDE; |
302 | status = do_open_permission(rqstp, resfh, open, accmode); | 302 | status = do_open_permission(rqstp, resfh, open, accmode); |
303 | set_change_info(&open->op_cinfo, current_fh); | 303 | set_change_info(&open->op_cinfo, current_fh); |
304 | fh_dup2(current_fh, resfh); | 304 | fh_dup2(current_fh, resfh); |
305 | out: | 305 | out: |
306 | fh_put(resfh); | 306 | fh_put(resfh); |
307 | kfree(resfh); | 307 | kfree(resfh); |
308 | return status; | 308 | return status; |
309 | } | 309 | } |
310 | 310 | ||
311 | static __be32 | 311 | static __be32 |
312 | do_open_fhandle(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | 312 | do_open_fhandle(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open) |
313 | { | 313 | { |
314 | struct svc_fh *current_fh = &cstate->current_fh; | 314 | struct svc_fh *current_fh = &cstate->current_fh; |
315 | __be32 status; | 315 | __be32 status; |
316 | int accmode = 0; | 316 | int accmode = 0; |
317 | 317 | ||
318 | /* We don't know the target directory, and therefore can not | 318 | /* We don't know the target directory, and therefore can not |
319 | * set the change info | 319 | * set the change info |
320 | */ | 320 | */ |
321 | 321 | ||
322 | memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); | 322 | memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); |
323 | 323 | ||
324 | nfsd4_set_open_owner_reply_cache(cstate, open, current_fh); | 324 | nfsd4_set_open_owner_reply_cache(cstate, open, current_fh); |
325 | 325 | ||
326 | open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && | 326 | open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && |
327 | (open->op_iattr.ia_size == 0); | 327 | (open->op_iattr.ia_size == 0); |
328 | /* | 328 | /* |
329 | * In the delegation case, the client is telling us about an | 329 | * In the delegation case, the client is telling us about an |
330 | * open that it *already* performed locally, some time ago. We | 330 | * open that it *already* performed locally, some time ago. We |
331 | * should let it succeed now if possible. | 331 | * should let it succeed now if possible. |
332 | * | 332 | * |
333 | * In the case of a CLAIM_FH open, on the other hand, the client | 333 | * In the case of a CLAIM_FH open, on the other hand, the client |
334 | * may be counting on us to enforce permissions (the Linux 4.1 | 334 | * may be counting on us to enforce permissions (the Linux 4.1 |
335 | * client uses this for normal opens, for example). | 335 | * client uses this for normal opens, for example). |
336 | */ | 336 | */ |
337 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH) | 337 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH) |
338 | accmode = NFSD_MAY_OWNER_OVERRIDE; | 338 | accmode = NFSD_MAY_OWNER_OVERRIDE; |
339 | 339 | ||
340 | status = do_open_permission(rqstp, current_fh, open, accmode); | 340 | status = do_open_permission(rqstp, current_fh, open, accmode); |
341 | 341 | ||
342 | return status; | 342 | return status; |
343 | } | 343 | } |
344 | 344 | ||
345 | static void | 345 | static void |
346 | copy_clientid(clientid_t *clid, struct nfsd4_session *session) | 346 | copy_clientid(clientid_t *clid, struct nfsd4_session *session) |
347 | { | 347 | { |
348 | struct nfsd4_sessionid *sid = | 348 | struct nfsd4_sessionid *sid = |
349 | (struct nfsd4_sessionid *)session->se_sessionid.data; | 349 | (struct nfsd4_sessionid *)session->se_sessionid.data; |
350 | 350 | ||
351 | clid->cl_boot = sid->clientid.cl_boot; | 351 | clid->cl_boot = sid->clientid.cl_boot; |
352 | clid->cl_id = sid->clientid.cl_id; | 352 | clid->cl_id = sid->clientid.cl_id; |
353 | } | 353 | } |
354 | 354 | ||
355 | static __be32 | 355 | static __be32 |
356 | nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 356 | nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
357 | struct nfsd4_open *open) | 357 | struct nfsd4_open *open) |
358 | { | 358 | { |
359 | __be32 status; | 359 | __be32 status; |
360 | struct nfsd4_compoundres *resp; | 360 | struct nfsd4_compoundres *resp; |
361 | struct net *net = SVC_NET(rqstp); | 361 | struct net *net = SVC_NET(rqstp); |
362 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 362 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
363 | 363 | ||
364 | dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", | 364 | dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", |
365 | (int)open->op_fname.len, open->op_fname.data, | 365 | (int)open->op_fname.len, open->op_fname.data, |
366 | open->op_openowner); | 366 | open->op_openowner); |
367 | 367 | ||
368 | /* This check required by spec. */ | 368 | /* This check required by spec. */ |
369 | if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) | 369 | if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) |
370 | return nfserr_inval; | 370 | return nfserr_inval; |
371 | 371 | ||
372 | open->op_created = 0; | 372 | open->op_created = 0; |
373 | /* | 373 | /* |
374 | * RFC5661 18.51.3 | 374 | * RFC5661 18.51.3 |
375 | * Before RECLAIM_COMPLETE done, server should deny new lock | 375 | * Before RECLAIM_COMPLETE done, server should deny new lock |
376 | */ | 376 | */ |
377 | if (nfsd4_has_session(cstate) && | 377 | if (nfsd4_has_session(cstate) && |
378 | !test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, | 378 | !test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, |
379 | &cstate->session->se_client->cl_flags) && | 379 | &cstate->session->se_client->cl_flags) && |
380 | open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) | 380 | open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) |
381 | return nfserr_grace; | 381 | return nfserr_grace; |
382 | 382 | ||
383 | if (nfsd4_has_session(cstate)) | 383 | if (nfsd4_has_session(cstate)) |
384 | copy_clientid(&open->op_clientid, cstate->session); | 384 | copy_clientid(&open->op_clientid, cstate->session); |
385 | 385 | ||
386 | nfs4_lock_state(); | 386 | nfs4_lock_state(); |
387 | 387 | ||
388 | /* check seqid for replay. set nfs4_owner */ | 388 | /* check seqid for replay. set nfs4_owner */ |
389 | resp = rqstp->rq_resp; | 389 | resp = rqstp->rq_resp; |
390 | status = nfsd4_process_open1(&resp->cstate, open, nn); | 390 | status = nfsd4_process_open1(&resp->cstate, open, nn); |
391 | if (status == nfserr_replay_me) { | 391 | if (status == nfserr_replay_me) { |
392 | struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; | 392 | struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; |
393 | fh_put(&cstate->current_fh); | 393 | fh_put(&cstate->current_fh); |
394 | fh_copy_shallow(&cstate->current_fh.fh_handle, | 394 | fh_copy_shallow(&cstate->current_fh.fh_handle, |
395 | &rp->rp_openfh); | 395 | &rp->rp_openfh); |
396 | status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); | 396 | status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); |
397 | if (status) | 397 | if (status) |
398 | dprintk("nfsd4_open: replay failed" | 398 | dprintk("nfsd4_open: replay failed" |
399 | " restoring previous filehandle\n"); | 399 | " restoring previous filehandle\n"); |
400 | else | 400 | else |
401 | status = nfserr_replay_me; | 401 | status = nfserr_replay_me; |
402 | } | 402 | } |
403 | if (status) | 403 | if (status) |
404 | goto out; | 404 | goto out; |
405 | if (open->op_xdr_error) { | 405 | if (open->op_xdr_error) { |
406 | status = open->op_xdr_error; | 406 | status = open->op_xdr_error; |
407 | goto out; | 407 | goto out; |
408 | } | 408 | } |
409 | 409 | ||
410 | status = nfsd4_check_open_attributes(rqstp, cstate, open); | 410 | status = nfsd4_check_open_attributes(rqstp, cstate, open); |
411 | if (status) | 411 | if (status) |
412 | goto out; | 412 | goto out; |
413 | 413 | ||
414 | /* Openowner is now set, so sequence id will get bumped. Now we need | 414 | /* Openowner is now set, so sequence id will get bumped. Now we need |
415 | * these checks before we do any creates: */ | 415 | * these checks before we do any creates: */ |
416 | status = nfserr_grace; | 416 | status = nfserr_grace; |
417 | if (locks_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) | 417 | if (locks_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) |
418 | goto out; | 418 | goto out; |
419 | status = nfserr_no_grace; | 419 | status = nfserr_no_grace; |
420 | if (!locks_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | 420 | if (!locks_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) |
421 | goto out; | 421 | goto out; |
422 | 422 | ||
423 | switch (open->op_claim_type) { | 423 | switch (open->op_claim_type) { |
424 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | 424 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: |
425 | case NFS4_OPEN_CLAIM_NULL: | 425 | case NFS4_OPEN_CLAIM_NULL: |
426 | status = do_open_lookup(rqstp, cstate, open); | 426 | status = do_open_lookup(rqstp, cstate, open); |
427 | if (status) | 427 | if (status) |
428 | goto out; | 428 | goto out; |
429 | break; | 429 | break; |
430 | case NFS4_OPEN_CLAIM_PREVIOUS: | 430 | case NFS4_OPEN_CLAIM_PREVIOUS: |
431 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 431 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
432 | status = nfs4_check_open_reclaim(&open->op_clientid, | 432 | status = nfs4_check_open_reclaim(&open->op_clientid, |
433 | cstate->minorversion, | 433 | cstate->minorversion, |
434 | nn); | 434 | nn); |
435 | if (status) | 435 | if (status) |
436 | goto out; | 436 | goto out; |
437 | case NFS4_OPEN_CLAIM_FH: | 437 | case NFS4_OPEN_CLAIM_FH: |
438 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: | 438 | case NFS4_OPEN_CLAIM_DELEG_CUR_FH: |
439 | status = do_open_fhandle(rqstp, cstate, open); | 439 | status = do_open_fhandle(rqstp, cstate, open); |
440 | if (status) | 440 | if (status) |
441 | goto out; | 441 | goto out; |
442 | break; | 442 | break; |
443 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: | 443 | case NFS4_OPEN_CLAIM_DELEG_PREV_FH: |
444 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: | 444 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: |
445 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 445 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
446 | dprintk("NFSD: unsupported OPEN claim type %d\n", | 446 | dprintk("NFSD: unsupported OPEN claim type %d\n", |
447 | open->op_claim_type); | 447 | open->op_claim_type); |
448 | status = nfserr_notsupp; | 448 | status = nfserr_notsupp; |
449 | goto out; | 449 | goto out; |
450 | default: | 450 | default: |
451 | dprintk("NFSD: Invalid OPEN claim type %d\n", | 451 | dprintk("NFSD: Invalid OPEN claim type %d\n", |
452 | open->op_claim_type); | 452 | open->op_claim_type); |
453 | status = nfserr_inval; | 453 | status = nfserr_inval; |
454 | goto out; | 454 | goto out; |
455 | } | 455 | } |
456 | /* | 456 | /* |
457 | * nfsd4_process_open2() does the actual opening of the file. If | 457 | * nfsd4_process_open2() does the actual opening of the file. If |
458 | * successful, it (1) truncates the file if open->op_truncate was | 458 | * successful, it (1) truncates the file if open->op_truncate was |
459 | * set, (2) sets open->op_stateid, (3) sets open->op_delegation. | 459 | * set, (2) sets open->op_stateid, (3) sets open->op_delegation. |
460 | */ | 460 | */ |
461 | status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); | 461 | status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); |
462 | WARN_ON(status && open->op_created); | 462 | WARN_ON(status && open->op_created); |
463 | out: | 463 | out: |
464 | nfsd4_cleanup_open_state(open, status); | 464 | nfsd4_cleanup_open_state(open, status); |
465 | if (open->op_openowner && !nfsd4_has_session(cstate)) | 465 | if (open->op_openowner && !nfsd4_has_session(cstate)) |
466 | cstate->replay_owner = &open->op_openowner->oo_owner; | 466 | cstate->replay_owner = &open->op_openowner->oo_owner; |
467 | nfsd4_bump_seqid(cstate, status); | 467 | nfsd4_bump_seqid(cstate, status); |
468 | if (!cstate->replay_owner) | 468 | if (!cstate->replay_owner) |
469 | nfs4_unlock_state(); | 469 | nfs4_unlock_state(); |
470 | return status; | 470 | return status; |
471 | } | 471 | } |
472 | 472 | ||
473 | /* | 473 | /* |
474 | * OPEN is the only seqid-mutating operation whose decoding can fail | 474 | * OPEN is the only seqid-mutating operation whose decoding can fail |
475 | * with a seqid-mutating error (specifically, decoding of user names in | 475 | * with a seqid-mutating error (specifically, decoding of user names in |
476 | * the attributes). Therefore we have to do some processing to look up | 476 | * the attributes). Therefore we have to do some processing to look up |
477 | * the stateowner so that we can bump the seqid. | 477 | * the stateowner so that we can bump the seqid. |
478 | */ | 478 | */ |
479 | static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_op *op) | 479 | static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_op *op) |
480 | { | 480 | { |
481 | struct nfsd4_open *open = (struct nfsd4_open *)&op->u; | 481 | struct nfsd4_open *open = (struct nfsd4_open *)&op->u; |
482 | 482 | ||
483 | if (!seqid_mutating_err(ntohl(op->status))) | 483 | if (!seqid_mutating_err(ntohl(op->status))) |
484 | return op->status; | 484 | return op->status; |
485 | if (nfsd4_has_session(cstate)) | 485 | if (nfsd4_has_session(cstate)) |
486 | return op->status; | 486 | return op->status; |
487 | open->op_xdr_error = op->status; | 487 | open->op_xdr_error = op->status; |
488 | return nfsd4_open(rqstp, cstate, open); | 488 | return nfsd4_open(rqstp, cstate, open); |
489 | } | 489 | } |
490 | 490 | ||
491 | /* | 491 | /* |
492 | * filehandle-manipulating ops. | 492 | * filehandle-manipulating ops. |
493 | */ | 493 | */ |
494 | static __be32 | 494 | static __be32 |
495 | nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 495 | nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
496 | struct svc_fh **getfh) | 496 | struct svc_fh **getfh) |
497 | { | 497 | { |
498 | if (!cstate->current_fh.fh_dentry) | 498 | if (!cstate->current_fh.fh_dentry) |
499 | return nfserr_nofilehandle; | 499 | return nfserr_nofilehandle; |
500 | 500 | ||
501 | *getfh = &cstate->current_fh; | 501 | *getfh = &cstate->current_fh; |
502 | return nfs_ok; | 502 | return nfs_ok; |
503 | } | 503 | } |
504 | 504 | ||
505 | static __be32 | 505 | static __be32 |
506 | nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 506 | nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
507 | struct nfsd4_putfh *putfh) | 507 | struct nfsd4_putfh *putfh) |
508 | { | 508 | { |
509 | fh_put(&cstate->current_fh); | 509 | fh_put(&cstate->current_fh); |
510 | cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; | 510 | cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; |
511 | memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, | 511 | memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, |
512 | putfh->pf_fhlen); | 512 | putfh->pf_fhlen); |
513 | return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS); | 513 | return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS); |
514 | } | 514 | } |
515 | 515 | ||
516 | static __be32 | 516 | static __be32 |
517 | nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 517 | nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
518 | void *arg) | 518 | void *arg) |
519 | { | 519 | { |
520 | __be32 status; | 520 | __be32 status; |
521 | 521 | ||
522 | fh_put(&cstate->current_fh); | 522 | fh_put(&cstate->current_fh); |
523 | status = exp_pseudoroot(rqstp, &cstate->current_fh); | 523 | status = exp_pseudoroot(rqstp, &cstate->current_fh); |
524 | return status; | 524 | return status; |
525 | } | 525 | } |
526 | 526 | ||
527 | static __be32 | 527 | static __be32 |
528 | nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 528 | nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
529 | void *arg) | 529 | void *arg) |
530 | { | 530 | { |
531 | if (!cstate->save_fh.fh_dentry) | 531 | if (!cstate->save_fh.fh_dentry) |
532 | return nfserr_restorefh; | 532 | return nfserr_restorefh; |
533 | 533 | ||
534 | fh_dup2(&cstate->current_fh, &cstate->save_fh); | 534 | fh_dup2(&cstate->current_fh, &cstate->save_fh); |
535 | if (HAS_STATE_ID(cstate, SAVED_STATE_ID_FLAG)) { | 535 | if (HAS_STATE_ID(cstate, SAVED_STATE_ID_FLAG)) { |
536 | memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t)); | 536 | memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t)); |
537 | SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); | 537 | SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); |
538 | } | 538 | } |
539 | return nfs_ok; | 539 | return nfs_ok; |
540 | } | 540 | } |
541 | 541 | ||
542 | static __be32 | 542 | static __be32 |
543 | nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 543 | nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
544 | void *arg) | 544 | void *arg) |
545 | { | 545 | { |
546 | if (!cstate->current_fh.fh_dentry) | 546 | if (!cstate->current_fh.fh_dentry) |
547 | return nfserr_nofilehandle; | 547 | return nfserr_nofilehandle; |
548 | 548 | ||
549 | fh_dup2(&cstate->save_fh, &cstate->current_fh); | 549 | fh_dup2(&cstate->save_fh, &cstate->current_fh); |
550 | if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) { | 550 | if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) { |
551 | memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t)); | 551 | memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t)); |
552 | SET_STATE_ID(cstate, SAVED_STATE_ID_FLAG); | 552 | SET_STATE_ID(cstate, SAVED_STATE_ID_FLAG); |
553 | } | 553 | } |
554 | return nfs_ok; | 554 | return nfs_ok; |
555 | } | 555 | } |
556 | 556 | ||
557 | /* | 557 | /* |
558 | * misc nfsv4 ops | 558 | * misc nfsv4 ops |
559 | */ | 559 | */ |
560 | static __be32 | 560 | static __be32 |
561 | nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 561 | nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
562 | struct nfsd4_access *access) | 562 | struct nfsd4_access *access) |
563 | { | 563 | { |
564 | if (access->ac_req_access & ~NFS3_ACCESS_FULL) | 564 | if (access->ac_req_access & ~NFS3_ACCESS_FULL) |
565 | return nfserr_inval; | 565 | return nfserr_inval; |
566 | 566 | ||
567 | access->ac_resp_access = access->ac_req_access; | 567 | access->ac_resp_access = access->ac_req_access; |
568 | return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access, | 568 | return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access, |
569 | &access->ac_supported); | 569 | &access->ac_supported); |
570 | } | 570 | } |
571 | 571 | ||
572 | static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) | 572 | static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) |
573 | { | 573 | { |
574 | __be32 verf[2]; | 574 | __be32 verf[2]; |
575 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 575 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
576 | 576 | ||
577 | verf[0] = (__be32)nn->nfssvc_boot.tv_sec; | 577 | verf[0] = (__be32)nn->nfssvc_boot.tv_sec; |
578 | verf[1] = (__be32)nn->nfssvc_boot.tv_usec; | 578 | verf[1] = (__be32)nn->nfssvc_boot.tv_usec; |
579 | memcpy(verifier->data, verf, sizeof(verifier->data)); | 579 | memcpy(verifier->data, verf, sizeof(verifier->data)); |
580 | } | 580 | } |
581 | 581 | ||
582 | static __be32 | 582 | static __be32 |
583 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 583 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
584 | struct nfsd4_commit *commit) | 584 | struct nfsd4_commit *commit) |
585 | { | 585 | { |
586 | gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp)); | 586 | gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp)); |
587 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, | 587 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, |
588 | commit->co_count); | 588 | commit->co_count); |
589 | } | 589 | } |
590 | 590 | ||
591 | static __be32 | 591 | static __be32 |
592 | nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 592 | nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
593 | struct nfsd4_create *create) | 593 | struct nfsd4_create *create) |
594 | { | 594 | { |
595 | struct svc_fh resfh; | 595 | struct svc_fh resfh; |
596 | __be32 status; | 596 | __be32 status; |
597 | dev_t rdev; | 597 | dev_t rdev; |
598 | 598 | ||
599 | fh_init(&resfh, NFS4_FHSIZE); | 599 | fh_init(&resfh, NFS4_FHSIZE); |
600 | 600 | ||
601 | status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, | 601 | status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, |
602 | NFSD_MAY_CREATE); | 602 | NFSD_MAY_CREATE); |
603 | if (status) | 603 | if (status) |
604 | return status; | 604 | return status; |
605 | 605 | ||
606 | status = check_attr_support(rqstp, cstate, create->cr_bmval, | 606 | status = check_attr_support(rqstp, cstate, create->cr_bmval, |
607 | nfsd_attrmask); | 607 | nfsd_attrmask); |
608 | if (status) | 608 | if (status) |
609 | return status; | 609 | return status; |
610 | 610 | ||
611 | switch (create->cr_type) { | 611 | switch (create->cr_type) { |
612 | case NF4LNK: | 612 | case NF4LNK: |
613 | /* ugh! we have to null-terminate the linktext, or | 613 | /* ugh! we have to null-terminate the linktext, or |
614 | * vfs_symlink() will choke. it is always safe to | 614 | * vfs_symlink() will choke. it is always safe to |
615 | * null-terminate by brute force, since at worst we | 615 | * null-terminate by brute force, since at worst we |
616 | * will overwrite the first byte of the create namelen | 616 | * will overwrite the first byte of the create namelen |
617 | * in the XDR buffer, which has already been extracted | 617 | * in the XDR buffer, which has already been extracted |
618 | * during XDR decode. | 618 | * during XDR decode. |
619 | */ | 619 | */ |
620 | create->cr_linkname[create->cr_linklen] = 0; | 620 | create->cr_linkname[create->cr_linklen] = 0; |
621 | 621 | ||
622 | status = nfsd_symlink(rqstp, &cstate->current_fh, | 622 | status = nfsd_symlink(rqstp, &cstate->current_fh, |
623 | create->cr_name, create->cr_namelen, | 623 | create->cr_name, create->cr_namelen, |
624 | create->cr_linkname, create->cr_linklen, | 624 | create->cr_linkname, create->cr_linklen, |
625 | &resfh, &create->cr_iattr); | 625 | &resfh, &create->cr_iattr); |
626 | break; | 626 | break; |
627 | 627 | ||
628 | case NF4BLK: | 628 | case NF4BLK: |
629 | rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); | 629 | rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); |
630 | if (MAJOR(rdev) != create->cr_specdata1 || | 630 | if (MAJOR(rdev) != create->cr_specdata1 || |
631 | MINOR(rdev) != create->cr_specdata2) | 631 | MINOR(rdev) != create->cr_specdata2) |
632 | return nfserr_inval; | 632 | return nfserr_inval; |
633 | status = nfsd_create(rqstp, &cstate->current_fh, | 633 | status = nfsd_create(rqstp, &cstate->current_fh, |
634 | create->cr_name, create->cr_namelen, | 634 | create->cr_name, create->cr_namelen, |
635 | &create->cr_iattr, S_IFBLK, rdev, &resfh); | 635 | &create->cr_iattr, S_IFBLK, rdev, &resfh); |
636 | break; | 636 | break; |
637 | 637 | ||
638 | case NF4CHR: | 638 | case NF4CHR: |
639 | rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); | 639 | rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); |
640 | if (MAJOR(rdev) != create->cr_specdata1 || | 640 | if (MAJOR(rdev) != create->cr_specdata1 || |
641 | MINOR(rdev) != create->cr_specdata2) | 641 | MINOR(rdev) != create->cr_specdata2) |
642 | return nfserr_inval; | 642 | return nfserr_inval; |
643 | status = nfsd_create(rqstp, &cstate->current_fh, | 643 | status = nfsd_create(rqstp, &cstate->current_fh, |
644 | create->cr_name, create->cr_namelen, | 644 | create->cr_name, create->cr_namelen, |
645 | &create->cr_iattr,S_IFCHR, rdev, &resfh); | 645 | &create->cr_iattr,S_IFCHR, rdev, &resfh); |
646 | break; | 646 | break; |
647 | 647 | ||
648 | case NF4SOCK: | 648 | case NF4SOCK: |
649 | status = nfsd_create(rqstp, &cstate->current_fh, | 649 | status = nfsd_create(rqstp, &cstate->current_fh, |
650 | create->cr_name, create->cr_namelen, | 650 | create->cr_name, create->cr_namelen, |
651 | &create->cr_iattr, S_IFSOCK, 0, &resfh); | 651 | &create->cr_iattr, S_IFSOCK, 0, &resfh); |
652 | break; | 652 | break; |
653 | 653 | ||
654 | case NF4FIFO: | 654 | case NF4FIFO: |
655 | status = nfsd_create(rqstp, &cstate->current_fh, | 655 | status = nfsd_create(rqstp, &cstate->current_fh, |
656 | create->cr_name, create->cr_namelen, | 656 | create->cr_name, create->cr_namelen, |
657 | &create->cr_iattr, S_IFIFO, 0, &resfh); | 657 | &create->cr_iattr, S_IFIFO, 0, &resfh); |
658 | break; | 658 | break; |
659 | 659 | ||
660 | case NF4DIR: | 660 | case NF4DIR: |
661 | create->cr_iattr.ia_valid &= ~ATTR_SIZE; | 661 | create->cr_iattr.ia_valid &= ~ATTR_SIZE; |
662 | status = nfsd_create(rqstp, &cstate->current_fh, | 662 | status = nfsd_create(rqstp, &cstate->current_fh, |
663 | create->cr_name, create->cr_namelen, | 663 | create->cr_name, create->cr_namelen, |
664 | &create->cr_iattr, S_IFDIR, 0, &resfh); | 664 | &create->cr_iattr, S_IFDIR, 0, &resfh); |
665 | break; | 665 | break; |
666 | 666 | ||
667 | default: | 667 | default: |
668 | status = nfserr_badtype; | 668 | status = nfserr_badtype; |
669 | } | 669 | } |
670 | 670 | ||
671 | if (status) | 671 | if (status) |
672 | goto out; | 672 | goto out; |
673 | 673 | ||
674 | if (create->cr_label.len) | 674 | if (create->cr_label.len) |
675 | nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); | 675 | nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); |
676 | 676 | ||
677 | if (create->cr_acl != NULL) | 677 | if (create->cr_acl != NULL) |
678 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, | 678 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, |
679 | create->cr_bmval); | 679 | create->cr_bmval); |
680 | 680 | ||
681 | fh_unlock(&cstate->current_fh); | 681 | fh_unlock(&cstate->current_fh); |
682 | set_change_info(&create->cr_cinfo, &cstate->current_fh); | 682 | set_change_info(&create->cr_cinfo, &cstate->current_fh); |
683 | fh_dup2(&cstate->current_fh, &resfh); | 683 | fh_dup2(&cstate->current_fh, &resfh); |
684 | out: | 684 | out: |
685 | fh_put(&resfh); | 685 | fh_put(&resfh); |
686 | return status; | 686 | return status; |
687 | } | 687 | } |
688 | 688 | ||
689 | static __be32 | 689 | static __be32 |
690 | nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 690 | nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
691 | struct nfsd4_getattr *getattr) | 691 | struct nfsd4_getattr *getattr) |
692 | { | 692 | { |
693 | __be32 status; | 693 | __be32 status; |
694 | 694 | ||
695 | status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); | 695 | status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); |
696 | if (status) | 696 | if (status) |
697 | return status; | 697 | return status; |
698 | 698 | ||
699 | if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) | 699 | if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) |
700 | return nfserr_inval; | 700 | return nfserr_inval; |
701 | 701 | ||
702 | getattr->ga_bmval[0] &= nfsd_suppattrs0(cstate->minorversion); | 702 | getattr->ga_bmval[0] &= nfsd_suppattrs0(cstate->minorversion); |
703 | getattr->ga_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); | 703 | getattr->ga_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); |
704 | getattr->ga_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); | 704 | getattr->ga_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); |
705 | 705 | ||
706 | getattr->ga_fhp = &cstate->current_fh; | 706 | getattr->ga_fhp = &cstate->current_fh; |
707 | return nfs_ok; | 707 | return nfs_ok; |
708 | } | 708 | } |
709 | 709 | ||
710 | static __be32 | 710 | static __be32 |
711 | nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 711 | nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
712 | struct nfsd4_link *link) | 712 | struct nfsd4_link *link) |
713 | { | 713 | { |
714 | __be32 status = nfserr_nofilehandle; | 714 | __be32 status = nfserr_nofilehandle; |
715 | 715 | ||
716 | if (!cstate->save_fh.fh_dentry) | 716 | if (!cstate->save_fh.fh_dentry) |
717 | return status; | 717 | return status; |
718 | status = nfsd_link(rqstp, &cstate->current_fh, | 718 | status = nfsd_link(rqstp, &cstate->current_fh, |
719 | link->li_name, link->li_namelen, &cstate->save_fh); | 719 | link->li_name, link->li_namelen, &cstate->save_fh); |
720 | if (!status) | 720 | if (!status) |
721 | set_change_info(&link->li_cinfo, &cstate->current_fh); | 721 | set_change_info(&link->li_cinfo, &cstate->current_fh); |
722 | return status; | 722 | return status; |
723 | } | 723 | } |
724 | 724 | ||
725 | static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh) | 725 | static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh) |
726 | { | 726 | { |
727 | struct svc_fh tmp_fh; | 727 | struct svc_fh tmp_fh; |
728 | __be32 ret; | 728 | __be32 ret; |
729 | 729 | ||
730 | fh_init(&tmp_fh, NFS4_FHSIZE); | 730 | fh_init(&tmp_fh, NFS4_FHSIZE); |
731 | ret = exp_pseudoroot(rqstp, &tmp_fh); | 731 | ret = exp_pseudoroot(rqstp, &tmp_fh); |
732 | if (ret) | 732 | if (ret) |
733 | return ret; | 733 | return ret; |
734 | if (tmp_fh.fh_dentry == fh->fh_dentry) { | 734 | if (tmp_fh.fh_dentry == fh->fh_dentry) { |
735 | fh_put(&tmp_fh); | 735 | fh_put(&tmp_fh); |
736 | return nfserr_noent; | 736 | return nfserr_noent; |
737 | } | 737 | } |
738 | fh_put(&tmp_fh); | 738 | fh_put(&tmp_fh); |
739 | return nfsd_lookup(rqstp, fh, "..", 2, fh); | 739 | return nfsd_lookup(rqstp, fh, "..", 2, fh); |
740 | } | 740 | } |
741 | 741 | ||
742 | static __be32 | 742 | static __be32 |
743 | nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 743 | nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
744 | void *arg) | 744 | void *arg) |
745 | { | 745 | { |
746 | return nfsd4_do_lookupp(rqstp, &cstate->current_fh); | 746 | return nfsd4_do_lookupp(rqstp, &cstate->current_fh); |
747 | } | 747 | } |
748 | 748 | ||
749 | static __be32 | 749 | static __be32 |
750 | nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 750 | nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
751 | struct nfsd4_lookup *lookup) | 751 | struct nfsd4_lookup *lookup) |
752 | { | 752 | { |
753 | return nfsd_lookup(rqstp, &cstate->current_fh, | 753 | return nfsd_lookup(rqstp, &cstate->current_fh, |
754 | lookup->lo_name, lookup->lo_len, | 754 | lookup->lo_name, lookup->lo_len, |
755 | &cstate->current_fh); | 755 | &cstate->current_fh); |
756 | } | 756 | } |
757 | 757 | ||
758 | static __be32 | 758 | static __be32 |
759 | nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 759 | nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
760 | struct nfsd4_read *read) | 760 | struct nfsd4_read *read) |
761 | { | 761 | { |
762 | __be32 status; | 762 | __be32 status; |
763 | 763 | ||
764 | /* no need to check permission - this will be done in nfsd_read() */ | 764 | /* no need to check permission - this will be done in nfsd_read() */ |
765 | 765 | ||
766 | read->rd_filp = NULL; | 766 | read->rd_filp = NULL; |
767 | if (read->rd_offset >= OFFSET_MAX) | 767 | if (read->rd_offset >= OFFSET_MAX) |
768 | return nfserr_inval; | 768 | return nfserr_inval; |
769 | 769 | ||
770 | /* | 770 | /* |
771 | * If we do a zero copy read, then a client will see read data | 771 | * If we do a zero copy read, then a client will see read data |
772 | * that reflects the state of the file *after* performing the | 772 | * that reflects the state of the file *after* performing the |
773 | * following compound. | 773 | * following compound. |
774 | * | 774 | * |
775 | * To ensure proper ordering, we therefore turn off zero copy if | 775 | * To ensure proper ordering, we therefore turn off zero copy if |
776 | * the client wants us to do more in this compound: | 776 | * the client wants us to do more in this compound: |
777 | */ | 777 | */ |
778 | if (!nfsd4_last_compound_op(rqstp)) | 778 | if (!nfsd4_last_compound_op(rqstp)) |
779 | rqstp->rq_splice_ok = false; | 779 | rqstp->rq_splice_ok = false; |
780 | 780 | ||
781 | nfs4_lock_state(); | 781 | nfs4_lock_state(); |
782 | /* check stateid */ | 782 | /* check stateid */ |
783 | if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), | 783 | if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), |
784 | cstate, &read->rd_stateid, | 784 | cstate, &read->rd_stateid, |
785 | RD_STATE, &read->rd_filp))) { | 785 | RD_STATE, &read->rd_filp))) { |
786 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); | 786 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); |
787 | goto out; | 787 | goto out; |
788 | } | 788 | } |
789 | if (read->rd_filp) | 789 | if (read->rd_filp) |
790 | get_file(read->rd_filp); | 790 | get_file(read->rd_filp); |
791 | status = nfs_ok; | 791 | status = nfs_ok; |
792 | out: | 792 | out: |
793 | nfs4_unlock_state(); | 793 | nfs4_unlock_state(); |
794 | read->rd_rqstp = rqstp; | 794 | read->rd_rqstp = rqstp; |
795 | read->rd_fhp = &cstate->current_fh; | 795 | read->rd_fhp = &cstate->current_fh; |
796 | return status; | 796 | return status; |
797 | } | 797 | } |
798 | 798 | ||
799 | static __be32 | 799 | static __be32 |
800 | nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 800 | nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
801 | struct nfsd4_readdir *readdir) | 801 | struct nfsd4_readdir *readdir) |
802 | { | 802 | { |
803 | u64 cookie = readdir->rd_cookie; | 803 | u64 cookie = readdir->rd_cookie; |
804 | static const nfs4_verifier zeroverf; | 804 | static const nfs4_verifier zeroverf; |
805 | 805 | ||
806 | /* no need to check permission - this will be done in nfsd_readdir() */ | 806 | /* no need to check permission - this will be done in nfsd_readdir() */ |
807 | 807 | ||
808 | if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) | 808 | if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) |
809 | return nfserr_inval; | 809 | return nfserr_inval; |
810 | 810 | ||
811 | readdir->rd_bmval[0] &= nfsd_suppattrs0(cstate->minorversion); | 811 | readdir->rd_bmval[0] &= nfsd_suppattrs0(cstate->minorversion); |
812 | readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); | 812 | readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); |
813 | readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); | 813 | readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); |
814 | 814 | ||
815 | if ((cookie == 1) || (cookie == 2) || | 815 | if ((cookie == 1) || (cookie == 2) || |
816 | (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) | 816 | (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) |
817 | return nfserr_bad_cookie; | 817 | return nfserr_bad_cookie; |
818 | 818 | ||
819 | readdir->rd_rqstp = rqstp; | 819 | readdir->rd_rqstp = rqstp; |
820 | readdir->rd_fhp = &cstate->current_fh; | 820 | readdir->rd_fhp = &cstate->current_fh; |
821 | return nfs_ok; | 821 | return nfs_ok; |
822 | } | 822 | } |
823 | 823 | ||
824 | static __be32 | 824 | static __be32 |
825 | nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 825 | nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
826 | struct nfsd4_readlink *readlink) | 826 | struct nfsd4_readlink *readlink) |
827 | { | 827 | { |
828 | readlink->rl_rqstp = rqstp; | 828 | readlink->rl_rqstp = rqstp; |
829 | readlink->rl_fhp = &cstate->current_fh; | 829 | readlink->rl_fhp = &cstate->current_fh; |
830 | return nfs_ok; | 830 | return nfs_ok; |
831 | } | 831 | } |
832 | 832 | ||
833 | static __be32 | 833 | static __be32 |
834 | nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 834 | nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
835 | struct nfsd4_remove *remove) | 835 | struct nfsd4_remove *remove) |
836 | { | 836 | { |
837 | __be32 status; | 837 | __be32 status; |
838 | 838 | ||
839 | if (locks_in_grace(SVC_NET(rqstp))) | 839 | if (locks_in_grace(SVC_NET(rqstp))) |
840 | return nfserr_grace; | 840 | return nfserr_grace; |
841 | status = nfsd_unlink(rqstp, &cstate->current_fh, 0, | 841 | status = nfsd_unlink(rqstp, &cstate->current_fh, 0, |
842 | remove->rm_name, remove->rm_namelen); | 842 | remove->rm_name, remove->rm_namelen); |
843 | if (!status) { | 843 | if (!status) { |
844 | fh_unlock(&cstate->current_fh); | 844 | fh_unlock(&cstate->current_fh); |
845 | set_change_info(&remove->rm_cinfo, &cstate->current_fh); | 845 | set_change_info(&remove->rm_cinfo, &cstate->current_fh); |
846 | } | 846 | } |
847 | return status; | 847 | return status; |
848 | } | 848 | } |
849 | 849 | ||
850 | static __be32 | 850 | static __be32 |
851 | nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 851 | nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
852 | struct nfsd4_rename *rename) | 852 | struct nfsd4_rename *rename) |
853 | { | 853 | { |
854 | __be32 status = nfserr_nofilehandle; | 854 | __be32 status = nfserr_nofilehandle; |
855 | 855 | ||
856 | if (!cstate->save_fh.fh_dentry) | 856 | if (!cstate->save_fh.fh_dentry) |
857 | return status; | 857 | return status; |
858 | if (locks_in_grace(SVC_NET(rqstp)) && | 858 | if (locks_in_grace(SVC_NET(rqstp)) && |
859 | !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK)) | 859 | !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK)) |
860 | return nfserr_grace; | 860 | return nfserr_grace; |
861 | status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, | 861 | status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, |
862 | rename->rn_snamelen, &cstate->current_fh, | 862 | rename->rn_snamelen, &cstate->current_fh, |
863 | rename->rn_tname, rename->rn_tnamelen); | 863 | rename->rn_tname, rename->rn_tnamelen); |
864 | if (status) | 864 | if (status) |
865 | return status; | 865 | return status; |
866 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); | 866 | set_change_info(&rename->rn_sinfo, &cstate->current_fh); |
867 | set_change_info(&rename->rn_tinfo, &cstate->save_fh); | 867 | set_change_info(&rename->rn_tinfo, &cstate->save_fh); |
868 | return nfs_ok; | 868 | return nfs_ok; |
869 | } | 869 | } |
870 | 870 | ||
871 | static __be32 | 871 | static __be32 |
872 | nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 872 | nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
873 | struct nfsd4_secinfo *secinfo) | 873 | struct nfsd4_secinfo *secinfo) |
874 | { | 874 | { |
875 | struct svc_fh resfh; | 875 | struct svc_fh resfh; |
876 | struct svc_export *exp; | 876 | struct svc_export *exp; |
877 | struct dentry *dentry; | 877 | struct dentry *dentry; |
878 | __be32 err; | 878 | __be32 err; |
879 | 879 | ||
880 | fh_init(&resfh, NFS4_FHSIZE); | 880 | fh_init(&resfh, NFS4_FHSIZE); |
881 | err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC); | 881 | err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC); |
882 | if (err) | 882 | if (err) |
883 | return err; | 883 | return err; |
884 | err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, | 884 | err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, |
885 | secinfo->si_name, secinfo->si_namelen, | 885 | secinfo->si_name, secinfo->si_namelen, |
886 | &exp, &dentry); | 886 | &exp, &dentry); |
887 | if (err) | 887 | if (err) |
888 | return err; | 888 | return err; |
889 | if (dentry->d_inode == NULL) { | 889 | if (dentry->d_inode == NULL) { |
890 | exp_put(exp); | 890 | exp_put(exp); |
891 | err = nfserr_noent; | 891 | err = nfserr_noent; |
892 | } else | 892 | } else |
893 | secinfo->si_exp = exp; | 893 | secinfo->si_exp = exp; |
894 | dput(dentry); | 894 | dput(dentry); |
895 | if (cstate->minorversion) | 895 | if (cstate->minorversion) |
896 | /* See rfc 5661 section 2.6.3.1.1.8 */ | 896 | /* See rfc 5661 section 2.6.3.1.1.8 */ |
897 | fh_put(&cstate->current_fh); | 897 | fh_put(&cstate->current_fh); |
898 | return err; | 898 | return err; |
899 | } | 899 | } |
900 | 900 | ||
901 | static __be32 | 901 | static __be32 |
902 | nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 902 | nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
903 | struct nfsd4_secinfo_no_name *sin) | 903 | struct nfsd4_secinfo_no_name *sin) |
904 | { | 904 | { |
905 | __be32 err; | 905 | __be32 err; |
906 | 906 | ||
907 | switch (sin->sin_style) { | 907 | switch (sin->sin_style) { |
908 | case NFS4_SECINFO_STYLE4_CURRENT_FH: | 908 | case NFS4_SECINFO_STYLE4_CURRENT_FH: |
909 | break; | 909 | break; |
910 | case NFS4_SECINFO_STYLE4_PARENT: | 910 | case NFS4_SECINFO_STYLE4_PARENT: |
911 | err = nfsd4_do_lookupp(rqstp, &cstate->current_fh); | 911 | err = nfsd4_do_lookupp(rqstp, &cstate->current_fh); |
912 | if (err) | 912 | if (err) |
913 | return err; | 913 | return err; |
914 | break; | 914 | break; |
915 | default: | 915 | default: |
916 | return nfserr_inval; | 916 | return nfserr_inval; |
917 | } | 917 | } |
918 | exp_get(cstate->current_fh.fh_export); | 918 | exp_get(cstate->current_fh.fh_export); |
919 | sin->sin_exp = cstate->current_fh.fh_export; | 919 | sin->sin_exp = cstate->current_fh.fh_export; |
920 | fh_put(&cstate->current_fh); | 920 | fh_put(&cstate->current_fh); |
921 | return nfs_ok; | 921 | return nfs_ok; |
922 | } | 922 | } |
923 | 923 | ||
924 | static __be32 | 924 | static __be32 |
925 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 925 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
926 | struct nfsd4_setattr *setattr) | 926 | struct nfsd4_setattr *setattr) |
927 | { | 927 | { |
928 | __be32 status = nfs_ok; | 928 | __be32 status = nfs_ok; |
929 | int err; | 929 | int err; |
930 | 930 | ||
931 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { | 931 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { |
932 | nfs4_lock_state(); | 932 | nfs4_lock_state(); |
933 | status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, | 933 | status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate, |
934 | &setattr->sa_stateid, WR_STATE, NULL); | 934 | &setattr->sa_stateid, WR_STATE, NULL); |
935 | nfs4_unlock_state(); | 935 | nfs4_unlock_state(); |
936 | if (status) { | 936 | if (status) { |
937 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); | 937 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); |
938 | return status; | 938 | return status; |
939 | } | 939 | } |
940 | } | 940 | } |
941 | err = fh_want_write(&cstate->current_fh); | 941 | err = fh_want_write(&cstate->current_fh); |
942 | if (err) | 942 | if (err) |
943 | return nfserrno(err); | 943 | return nfserrno(err); |
944 | status = nfs_ok; | 944 | status = nfs_ok; |
945 | 945 | ||
946 | status = check_attr_support(rqstp, cstate, setattr->sa_bmval, | 946 | status = check_attr_support(rqstp, cstate, setattr->sa_bmval, |
947 | nfsd_attrmask); | 947 | nfsd_attrmask); |
948 | if (status) | 948 | if (status) |
949 | goto out; | 949 | goto out; |
950 | 950 | ||
951 | if (setattr->sa_acl != NULL) | 951 | if (setattr->sa_acl != NULL) |
952 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, | 952 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, |
953 | setattr->sa_acl); | 953 | setattr->sa_acl); |
954 | if (status) | 954 | if (status) |
955 | goto out; | 955 | goto out; |
956 | if (setattr->sa_label.len) | 956 | if (setattr->sa_label.len) |
957 | status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh, | 957 | status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh, |
958 | &setattr->sa_label); | 958 | &setattr->sa_label); |
959 | if (status) | 959 | if (status) |
960 | goto out; | 960 | goto out; |
961 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, | 961 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, |
962 | 0, (time_t)0); | 962 | 0, (time_t)0); |
963 | out: | 963 | out: |
964 | fh_drop_write(&cstate->current_fh); | 964 | fh_drop_write(&cstate->current_fh); |
965 | return status; | 965 | return status; |
966 | } | 966 | } |
967 | 967 | ||
968 | static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) | 968 | static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) |
969 | { | 969 | { |
970 | int i = 1; | 970 | int i = 1; |
971 | int buflen = write->wr_buflen; | 971 | int buflen = write->wr_buflen; |
972 | 972 | ||
973 | vec[0].iov_base = write->wr_head.iov_base; | 973 | vec[0].iov_base = write->wr_head.iov_base; |
974 | vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len); | 974 | vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len); |
975 | buflen -= vec[0].iov_len; | 975 | buflen -= vec[0].iov_len; |
976 | 976 | ||
977 | while (buflen) { | 977 | while (buflen) { |
978 | vec[i].iov_base = page_address(write->wr_pagelist[i - 1]); | 978 | vec[i].iov_base = page_address(write->wr_pagelist[i - 1]); |
979 | vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); | 979 | vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); |
980 | buflen -= vec[i].iov_len; | 980 | buflen -= vec[i].iov_len; |
981 | i++; | 981 | i++; |
982 | } | 982 | } |
983 | return i; | 983 | return i; |
984 | } | 984 | } |
985 | 985 | ||
986 | static __be32 | 986 | static __be32 |
987 | nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 987 | nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
988 | struct nfsd4_write *write) | 988 | struct nfsd4_write *write) |
989 | { | 989 | { |
990 | stateid_t *stateid = &write->wr_stateid; | 990 | stateid_t *stateid = &write->wr_stateid; |
991 | struct file *filp = NULL; | 991 | struct file *filp = NULL; |
992 | __be32 status = nfs_ok; | 992 | __be32 status = nfs_ok; |
993 | unsigned long cnt; | 993 | unsigned long cnt; |
994 | int nvecs; | 994 | int nvecs; |
995 | 995 | ||
996 | /* no need to check permission - this will be done in nfsd_write() */ | 996 | /* no need to check permission - this will be done in nfsd_write() */ |
997 | 997 | ||
998 | if (write->wr_offset >= OFFSET_MAX) | 998 | if (write->wr_offset >= OFFSET_MAX) |
999 | return nfserr_inval; | 999 | return nfserr_inval; |
1000 | 1000 | ||
1001 | nfs4_lock_state(); | 1001 | nfs4_lock_state(); |
1002 | status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), | 1002 | status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), |
1003 | cstate, stateid, WR_STATE, &filp); | 1003 | cstate, stateid, WR_STATE, &filp); |
1004 | if (status) { | 1004 | if (status) { |
1005 | nfs4_unlock_state(); | 1005 | nfs4_unlock_state(); |
1006 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); | 1006 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); |
1007 | return status; | 1007 | return status; |
1008 | } | 1008 | } |
1009 | if (filp) | 1009 | if (filp) |
1010 | get_file(filp); | 1010 | get_file(filp); |
1011 | nfs4_unlock_state(); | 1011 | nfs4_unlock_state(); |
1012 | 1012 | ||
1013 | cnt = write->wr_buflen; | 1013 | cnt = write->wr_buflen; |
1014 | write->wr_how_written = write->wr_stable_how; | 1014 | write->wr_how_written = write->wr_stable_how; |
1015 | gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp)); | 1015 | gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp)); |
1016 | 1016 | ||
1017 | nvecs = fill_in_write_vector(rqstp->rq_vec, write); | 1017 | nvecs = fill_in_write_vector(rqstp->rq_vec, write); |
1018 | WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); | 1018 | WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); |
1019 | 1019 | ||
1020 | status = nfsd_write(rqstp, &cstate->current_fh, filp, | 1020 | status = nfsd_write(rqstp, &cstate->current_fh, filp, |
1021 | write->wr_offset, rqstp->rq_vec, nvecs, | 1021 | write->wr_offset, rqstp->rq_vec, nvecs, |
1022 | &cnt, &write->wr_how_written); | 1022 | &cnt, &write->wr_how_written); |
1023 | if (filp) | 1023 | if (filp) |
1024 | fput(filp); | 1024 | fput(filp); |
1025 | 1025 | ||
1026 | write->wr_bytes_written = cnt; | 1026 | write->wr_bytes_written = cnt; |
1027 | 1027 | ||
1028 | return status; | 1028 | return status; |
1029 | } | 1029 | } |
1030 | 1030 | ||
1031 | /* This routine never returns NFS_OK! If there are no other errors, it | 1031 | /* This routine never returns NFS_OK! If there are no other errors, it |
1032 | * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the | 1032 | * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the |
1033 | * attributes matched. VERIFY is implemented by mapping NFSERR_SAME | 1033 | * attributes matched. VERIFY is implemented by mapping NFSERR_SAME |
1034 | * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. | 1034 | * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. |
1035 | */ | 1035 | */ |
1036 | static __be32 | 1036 | static __be32 |
1037 | _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1037 | _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1038 | struct nfsd4_verify *verify) | 1038 | struct nfsd4_verify *verify) |
1039 | { | 1039 | { |
1040 | __be32 *buf, *p; | 1040 | __be32 *buf, *p; |
1041 | int count; | 1041 | int count; |
1042 | __be32 status; | 1042 | __be32 status; |
1043 | 1043 | ||
1044 | status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); | 1044 | status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP); |
1045 | if (status) | 1045 | if (status) |
1046 | return status; | 1046 | return status; |
1047 | 1047 | ||
1048 | status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL); | 1048 | status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL); |
1049 | if (status) | 1049 | if (status) |
1050 | return status; | 1050 | return status; |
1051 | 1051 | ||
1052 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) | 1052 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) |
1053 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) | 1053 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) |
1054 | return nfserr_inval; | 1054 | return nfserr_inval; |
1055 | if (verify->ve_attrlen & 3) | 1055 | if (verify->ve_attrlen & 3) |
1056 | return nfserr_inval; | 1056 | return nfserr_inval; |
1057 | 1057 | ||
1058 | /* count in words: | 1058 | /* count in words: |
1059 | * bitmap_len(1) + bitmap(2) + attr_len(1) = 4 | 1059 | * bitmap_len(1) + bitmap(2) + attr_len(1) = 4 |
1060 | */ | 1060 | */ |
1061 | count = 4 + (verify->ve_attrlen >> 2); | 1061 | count = 4 + (verify->ve_attrlen >> 2); |
1062 | buf = kmalloc(count << 2, GFP_KERNEL); | 1062 | buf = kmalloc(count << 2, GFP_KERNEL); |
1063 | if (!buf) | 1063 | if (!buf) |
1064 | return nfserr_jukebox; | 1064 | return nfserr_jukebox; |
1065 | 1065 | ||
1066 | p = buf; | 1066 | p = buf; |
1067 | status = nfsd4_encode_fattr(&cstate->current_fh, | 1067 | status = nfsd4_encode_fattr(&cstate->current_fh, |
1068 | cstate->current_fh.fh_export, | 1068 | cstate->current_fh.fh_export, |
1069 | cstate->current_fh.fh_dentry, &p, | 1069 | cstate->current_fh.fh_dentry, &p, |
1070 | count, verify->ve_bmval, | 1070 | count, verify->ve_bmval, |
1071 | rqstp, 0); | 1071 | rqstp, 0); |
1072 | 1072 | ||
1073 | /* this means that nfsd4_encode_fattr() ran out of space */ | 1073 | /* this means that nfsd4_encode_fattr() ran out of space */ |
1074 | if (status == nfserr_resource) | 1074 | if (status == nfserr_resource) |
1075 | status = nfserr_not_same; | 1075 | status = nfserr_not_same; |
1076 | if (status) | 1076 | if (status) |
1077 | goto out_kfree; | 1077 | goto out_kfree; |
1078 | 1078 | ||
1079 | /* skip bitmap */ | 1079 | /* skip bitmap */ |
1080 | p = buf + 1 + ntohl(buf[0]); | 1080 | p = buf + 1 + ntohl(buf[0]); |
1081 | status = nfserr_not_same; | 1081 | status = nfserr_not_same; |
1082 | if (ntohl(*p++) != verify->ve_attrlen) | 1082 | if (ntohl(*p++) != verify->ve_attrlen) |
1083 | goto out_kfree; | 1083 | goto out_kfree; |
1084 | if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen)) | 1084 | if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen)) |
1085 | status = nfserr_same; | 1085 | status = nfserr_same; |
1086 | 1086 | ||
1087 | out_kfree: | 1087 | out_kfree: |
1088 | kfree(buf); | 1088 | kfree(buf); |
1089 | return status; | 1089 | return status; |
1090 | } | 1090 | } |
1091 | 1091 | ||
1092 | static __be32 | 1092 | static __be32 |
1093 | nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1093 | nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1094 | struct nfsd4_verify *verify) | 1094 | struct nfsd4_verify *verify) |
1095 | { | 1095 | { |
1096 | __be32 status; | 1096 | __be32 status; |
1097 | 1097 | ||
1098 | status = _nfsd4_verify(rqstp, cstate, verify); | 1098 | status = _nfsd4_verify(rqstp, cstate, verify); |
1099 | return status == nfserr_not_same ? nfs_ok : status; | 1099 | return status == nfserr_not_same ? nfs_ok : status; |
1100 | } | 1100 | } |
1101 | 1101 | ||
1102 | static __be32 | 1102 | static __be32 |
1103 | nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1103 | nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1104 | struct nfsd4_verify *verify) | 1104 | struct nfsd4_verify *verify) |
1105 | { | 1105 | { |
1106 | __be32 status; | 1106 | __be32 status; |
1107 | 1107 | ||
1108 | status = _nfsd4_verify(rqstp, cstate, verify); | 1108 | status = _nfsd4_verify(rqstp, cstate, verify); |
1109 | return status == nfserr_same ? nfs_ok : status; | 1109 | return status == nfserr_same ? nfs_ok : status; |
1110 | } | 1110 | } |
1111 | 1111 | ||
1112 | /* | 1112 | /* |
1113 | * NULL call. | 1113 | * NULL call. |
1114 | */ | 1114 | */ |
1115 | static __be32 | 1115 | static __be32 |
1116 | nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | 1116 | nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) |
1117 | { | 1117 | { |
1118 | return nfs_ok; | 1118 | return nfs_ok; |
1119 | } | 1119 | } |
1120 | 1120 | ||
1121 | static inline void nfsd4_increment_op_stats(u32 opnum) | 1121 | static inline void nfsd4_increment_op_stats(u32 opnum) |
1122 | { | 1122 | { |
1123 | if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP) | 1123 | if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP) |
1124 | nfsdstats.nfs4_opcount[opnum]++; | 1124 | nfsdstats.nfs4_opcount[opnum]++; |
1125 | } | 1125 | } |
1126 | 1126 | ||
1127 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, | 1127 | typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, |
1128 | void *); | 1128 | void *); |
1129 | typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op); | 1129 | typedef u32(*nfsd4op_rsize)(struct svc_rqst *, struct nfsd4_op *op); |
1130 | typedef void(*stateid_setter)(struct nfsd4_compound_state *, void *); | 1130 | typedef void(*stateid_setter)(struct nfsd4_compound_state *, void *); |
1131 | typedef void(*stateid_getter)(struct nfsd4_compound_state *, void *); | 1131 | typedef void(*stateid_getter)(struct nfsd4_compound_state *, void *); |
1132 | 1132 | ||
1133 | enum nfsd4_op_flags { | 1133 | enum nfsd4_op_flags { |
1134 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ | 1134 | ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */ |
1135 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ | 1135 | ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */ |
1136 | ALLOWED_AS_FIRST_OP = 1 << 2, /* ops reqired first in compound */ | 1136 | ALLOWED_AS_FIRST_OP = 1 << 2, /* ops reqired first in compound */ |
1137 | /* For rfc 5661 section 2.6.3.1.1: */ | 1137 | /* For rfc 5661 section 2.6.3.1.1: */ |
1138 | OP_HANDLES_WRONGSEC = 1 << 3, | 1138 | OP_HANDLES_WRONGSEC = 1 << 3, |
1139 | OP_IS_PUTFH_LIKE = 1 << 4, | 1139 | OP_IS_PUTFH_LIKE = 1 << 4, |
1140 | /* | 1140 | /* |
1141 | * These are the ops whose result size we estimate before | 1141 | * These are the ops whose result size we estimate before |
1142 | * encoding, to avoid performing an op then not being able to | 1142 | * encoding, to avoid performing an op then not being able to |
1143 | * respond or cache a response. This includes writes and setattrs | 1143 | * respond or cache a response. This includes writes and setattrs |
1144 | * as well as the operations usually called "nonidempotent": | 1144 | * as well as the operations usually called "nonidempotent": |
1145 | */ | 1145 | */ |
1146 | OP_MODIFIES_SOMETHING = 1 << 5, | 1146 | OP_MODIFIES_SOMETHING = 1 << 5, |
1147 | /* | 1147 | /* |
1148 | * Cache compounds containing these ops in the xid-based drc: | 1148 | * Cache compounds containing these ops in the xid-based drc: |
1149 | * We use the DRC for compounds containing non-idempotent | 1149 | * We use the DRC for compounds containing non-idempotent |
1150 | * operations, *except* those that are 4.1-specific (since | 1150 | * operations, *except* those that are 4.1-specific (since |
1151 | * sessions provide their own EOS), and except for stateful | 1151 | * sessions provide their own EOS), and except for stateful |
1152 | * operations other than setclientid and setclientid_confirm | 1152 | * operations other than setclientid and setclientid_confirm |
1153 | * (since sequence numbers provide EOS for open, lock, etc in | 1153 | * (since sequence numbers provide EOS for open, lock, etc in |
1154 | * the v4.0 case). | 1154 | * the v4.0 case). |
1155 | */ | 1155 | */ |
1156 | OP_CACHEME = 1 << 6, | 1156 | OP_CACHEME = 1 << 6, |
1157 | /* | 1157 | /* |
1158 | * These are ops which clear current state id. | 1158 | * These are ops which clear current state id. |
1159 | */ | 1159 | */ |
1160 | OP_CLEAR_STATEID = 1 << 7, | 1160 | OP_CLEAR_STATEID = 1 << 7, |
1161 | }; | 1161 | }; |
1162 | 1162 | ||
1163 | struct nfsd4_operation { | 1163 | struct nfsd4_operation { |
1164 | nfsd4op_func op_func; | 1164 | nfsd4op_func op_func; |
1165 | u32 op_flags; | 1165 | u32 op_flags; |
1166 | char *op_name; | 1166 | char *op_name; |
1167 | /* Try to get response size before operation */ | 1167 | /* Try to get response size before operation */ |
1168 | nfsd4op_rsize op_rsize_bop; | 1168 | nfsd4op_rsize op_rsize_bop; |
1169 | stateid_getter op_get_currentstateid; | 1169 | stateid_getter op_get_currentstateid; |
1170 | stateid_setter op_set_currentstateid; | 1170 | stateid_setter op_set_currentstateid; |
1171 | }; | 1171 | }; |
1172 | 1172 | ||
1173 | static struct nfsd4_operation nfsd4_ops[]; | 1173 | static struct nfsd4_operation nfsd4_ops[]; |
1174 | 1174 | ||
1175 | #ifdef NFSD_DEBUG | 1175 | #ifdef NFSD_DEBUG |
1176 | static const char *nfsd4_op_name(unsigned opnum); | 1176 | static const char *nfsd4_op_name(unsigned opnum); |
1177 | #endif | 1177 | #endif |
1178 | 1178 | ||
1179 | /* | 1179 | /* |
1180 | * Enforce NFSv4.1 COMPOUND ordering rules: | 1180 | * Enforce NFSv4.1 COMPOUND ordering rules: |
1181 | * | 1181 | * |
1182 | * Also note, enforced elsewhere: | 1182 | * Also note, enforced elsewhere: |
1183 | * - SEQUENCE other than as first op results in | 1183 | * - SEQUENCE other than as first op results in |
1184 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) | 1184 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) |
1185 | * - BIND_CONN_TO_SESSION must be the only op in its compound. | 1185 | * - BIND_CONN_TO_SESSION must be the only op in its compound. |
1186 | * (Enforced in nfsd4_bind_conn_to_session().) | 1186 | * (Enforced in nfsd4_bind_conn_to_session().) |
1187 | * - DESTROY_SESSION must be the final operation in a compound, if | 1187 | * - DESTROY_SESSION must be the final operation in a compound, if |
1188 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. | 1188 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. |
1189 | * (Enforced in nfsd4_destroy_session().) | 1189 | * (Enforced in nfsd4_destroy_session().) |
1190 | */ | 1190 | */ |
1191 | static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args) | 1191 | static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args) |
1192 | { | 1192 | { |
1193 | struct nfsd4_op *op = &args->ops[0]; | 1193 | struct nfsd4_op *op = &args->ops[0]; |
1194 | 1194 | ||
1195 | /* These ordering requirements don't apply to NFSv4.0: */ | 1195 | /* These ordering requirements don't apply to NFSv4.0: */ |
1196 | if (args->minorversion == 0) | 1196 | if (args->minorversion == 0) |
1197 | return nfs_ok; | 1197 | return nfs_ok; |
1198 | /* This is weird, but OK, not our problem: */ | 1198 | /* This is weird, but OK, not our problem: */ |
1199 | if (args->opcnt == 0) | 1199 | if (args->opcnt == 0) |
1200 | return nfs_ok; | 1200 | return nfs_ok; |
1201 | if (op->status == nfserr_op_illegal) | 1201 | if (op->status == nfserr_op_illegal) |
1202 | return nfs_ok; | 1202 | return nfs_ok; |
1203 | if (!(nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP)) | 1203 | if (!(nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP)) |
1204 | return nfserr_op_not_in_session; | 1204 | return nfserr_op_not_in_session; |
1205 | if (op->opnum == OP_SEQUENCE) | 1205 | if (op->opnum == OP_SEQUENCE) |
1206 | return nfs_ok; | 1206 | return nfs_ok; |
1207 | if (args->opcnt != 1) | 1207 | if (args->opcnt != 1) |
1208 | return nfserr_not_only_op; | 1208 | return nfserr_not_only_op; |
1209 | return nfs_ok; | 1209 | return nfs_ok; |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op) | 1212 | static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op) |
1213 | { | 1213 | { |
1214 | return &nfsd4_ops[op->opnum]; | 1214 | return &nfsd4_ops[op->opnum]; |
1215 | } | 1215 | } |
1216 | 1216 | ||
1217 | bool nfsd4_cache_this_op(struct nfsd4_op *op) | 1217 | bool nfsd4_cache_this_op(struct nfsd4_op *op) |
1218 | { | 1218 | { |
1219 | return OPDESC(op)->op_flags & OP_CACHEME; | 1219 | return OPDESC(op)->op_flags & OP_CACHEME; |
1220 | } | 1220 | } |
1221 | 1221 | ||
1222 | static bool need_wrongsec_check(struct svc_rqst *rqstp) | 1222 | static bool need_wrongsec_check(struct svc_rqst *rqstp) |
1223 | { | 1223 | { |
1224 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 1224 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
1225 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | 1225 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; |
1226 | struct nfsd4_op *this = &argp->ops[resp->opcnt - 1]; | 1226 | struct nfsd4_op *this = &argp->ops[resp->opcnt - 1]; |
1227 | struct nfsd4_op *next = &argp->ops[resp->opcnt]; | 1227 | struct nfsd4_op *next = &argp->ops[resp->opcnt]; |
1228 | struct nfsd4_operation *thisd; | 1228 | struct nfsd4_operation *thisd; |
1229 | struct nfsd4_operation *nextd; | 1229 | struct nfsd4_operation *nextd; |
1230 | 1230 | ||
1231 | thisd = OPDESC(this); | 1231 | thisd = OPDESC(this); |
1232 | /* | 1232 | /* |
1233 | * Most ops check wronsec on our own; only the putfh-like ops | 1233 | * Most ops check wronsec on our own; only the putfh-like ops |
1234 | * have special rules. | 1234 | * have special rules. |
1235 | */ | 1235 | */ |
1236 | if (!(thisd->op_flags & OP_IS_PUTFH_LIKE)) | 1236 | if (!(thisd->op_flags & OP_IS_PUTFH_LIKE)) |
1237 | return false; | 1237 | return false; |
1238 | /* | 1238 | /* |
1239 | * rfc 5661 2.6.3.1.1.6: don't bother erroring out a | 1239 | * rfc 5661 2.6.3.1.1.6: don't bother erroring out a |
1240 | * put-filehandle operation if we're not going to use the | 1240 | * put-filehandle operation if we're not going to use the |
1241 | * result: | 1241 | * result: |
1242 | */ | 1242 | */ |
1243 | if (argp->opcnt == resp->opcnt) | 1243 | if (argp->opcnt == resp->opcnt) |
1244 | return false; | 1244 | return false; |
1245 | 1245 | ||
1246 | nextd = OPDESC(next); | 1246 | nextd = OPDESC(next); |
1247 | /* | 1247 | /* |
1248 | * Rest of 2.6.3.1.1: certain operations will return WRONGSEC | 1248 | * Rest of 2.6.3.1.1: certain operations will return WRONGSEC |
1249 | * errors themselves as necessary; others should check for them | 1249 | * errors themselves as necessary; others should check for them |
1250 | * now: | 1250 | * now: |
1251 | */ | 1251 | */ |
1252 | return !(nextd->op_flags & OP_HANDLES_WRONGSEC); | 1252 | return !(nextd->op_flags & OP_HANDLES_WRONGSEC); |
1253 | } | 1253 | } |
1254 | 1254 | ||
1255 | /* | 1255 | /* |
1256 | * COMPOUND call. | 1256 | * COMPOUND call. |
1257 | */ | 1257 | */ |
1258 | static __be32 | 1258 | static __be32 |
1259 | nfsd4_proc_compound(struct svc_rqst *rqstp, | 1259 | nfsd4_proc_compound(struct svc_rqst *rqstp, |
1260 | struct nfsd4_compoundargs *args, | 1260 | struct nfsd4_compoundargs *args, |
1261 | struct nfsd4_compoundres *resp) | 1261 | struct nfsd4_compoundres *resp) |
1262 | { | 1262 | { |
1263 | struct nfsd4_op *op; | 1263 | struct nfsd4_op *op; |
1264 | struct nfsd4_operation *opdesc; | 1264 | struct nfsd4_operation *opdesc; |
1265 | struct nfsd4_compound_state *cstate = &resp->cstate; | 1265 | struct nfsd4_compound_state *cstate = &resp->cstate; |
1266 | int slack_bytes; | 1266 | int slack_bytes; |
1267 | u32 plen = 0; | 1267 | u32 plen = 0; |
1268 | __be32 status; | 1268 | __be32 status; |
1269 | 1269 | ||
1270 | resp->xbuf = &rqstp->rq_res; | 1270 | resp->xbuf = &rqstp->rq_res; |
1271 | resp->p = rqstp->rq_res.head[0].iov_base + | 1271 | resp->p = rqstp->rq_res.head[0].iov_base + |
1272 | rqstp->rq_res.head[0].iov_len; | 1272 | rqstp->rq_res.head[0].iov_len; |
1273 | resp->tagp = resp->p; | 1273 | resp->tagp = resp->p; |
1274 | /* reserve space for: taglen, tag, and opcnt */ | 1274 | /* reserve space for: taglen, tag, and opcnt */ |
1275 | resp->p += 2 + XDR_QUADLEN(args->taglen); | 1275 | resp->p += 2 + XDR_QUADLEN(args->taglen); |
1276 | resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE; | 1276 | resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE; |
1277 | resp->taglen = args->taglen; | 1277 | resp->taglen = args->taglen; |
1278 | resp->tag = args->tag; | 1278 | resp->tag = args->tag; |
1279 | resp->opcnt = 0; | 1279 | resp->opcnt = 0; |
1280 | resp->rqstp = rqstp; | 1280 | resp->rqstp = rqstp; |
1281 | resp->cstate.minorversion = args->minorversion; | 1281 | resp->cstate.minorversion = args->minorversion; |
1282 | resp->cstate.replay_owner = NULL; | 1282 | resp->cstate.replay_owner = NULL; |
1283 | resp->cstate.session = NULL; | 1283 | resp->cstate.session = NULL; |
1284 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); | 1284 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); |
1285 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); | 1285 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); |
1286 | /* | 1286 | /* |
1287 | * Don't use the deferral mechanism for NFSv4; compounds make it | 1287 | * Don't use the deferral mechanism for NFSv4; compounds make it |
1288 | * too hard to avoid non-idempotency problems. | 1288 | * too hard to avoid non-idempotency problems. |
1289 | */ | 1289 | */ |
1290 | rqstp->rq_usedeferral = 0; | 1290 | rqstp->rq_usedeferral = 0; |
1291 | 1291 | ||
1292 | /* | 1292 | /* |
1293 | * According to RFC3010, this takes precedence over all other errors. | 1293 | * According to RFC3010, this takes precedence over all other errors. |
1294 | */ | 1294 | */ |
1295 | status = nfserr_minor_vers_mismatch; | 1295 | status = nfserr_minor_vers_mismatch; |
1296 | if (args->minorversion > nfsd_supported_minorversion) | 1296 | if (nfsd_minorversion(args->minorversion, NFSD_TEST) <= 0) |
1297 | goto out; | 1297 | goto out; |
1298 | 1298 | ||
1299 | status = nfs41_check_op_ordering(args); | 1299 | status = nfs41_check_op_ordering(args); |
1300 | if (status) { | 1300 | if (status) { |
1301 | op = &args->ops[0]; | 1301 | op = &args->ops[0]; |
1302 | op->status = status; | 1302 | op->status = status; |
1303 | goto encode_op; | 1303 | goto encode_op; |
1304 | } | 1304 | } |
1305 | 1305 | ||
1306 | while (!status && resp->opcnt < args->opcnt) { | 1306 | while (!status && resp->opcnt < args->opcnt) { |
1307 | op = &args->ops[resp->opcnt++]; | 1307 | op = &args->ops[resp->opcnt++]; |
1308 | 1308 | ||
1309 | dprintk("nfsv4 compound op #%d/%d: %d (%s)\n", | 1309 | dprintk("nfsv4 compound op #%d/%d: %d (%s)\n", |
1310 | resp->opcnt, args->opcnt, op->opnum, | 1310 | resp->opcnt, args->opcnt, op->opnum, |
1311 | nfsd4_op_name(op->opnum)); | 1311 | nfsd4_op_name(op->opnum)); |
1312 | /* | 1312 | /* |
1313 | * The XDR decode routines may have pre-set op->status; | 1313 | * The XDR decode routines may have pre-set op->status; |
1314 | * for example, if there is a miscellaneous XDR error | 1314 | * for example, if there is a miscellaneous XDR error |
1315 | * it will be set to nfserr_bad_xdr. | 1315 | * it will be set to nfserr_bad_xdr. |
1316 | */ | 1316 | */ |
1317 | if (op->status) { | 1317 | if (op->status) { |
1318 | if (op->opnum == OP_OPEN) | 1318 | if (op->opnum == OP_OPEN) |
1319 | op->status = nfsd4_open_omfg(rqstp, cstate, op); | 1319 | op->status = nfsd4_open_omfg(rqstp, cstate, op); |
1320 | goto encode_op; | 1320 | goto encode_op; |
1321 | } | 1321 | } |
1322 | 1322 | ||
1323 | /* We must be able to encode a successful response to | 1323 | /* We must be able to encode a successful response to |
1324 | * this operation, with enough room left over to encode a | 1324 | * this operation, with enough room left over to encode a |
1325 | * failed response to the next operation. If we don't | 1325 | * failed response to the next operation. If we don't |
1326 | * have enough room, fail with ERR_RESOURCE. | 1326 | * have enough room, fail with ERR_RESOURCE. |
1327 | */ | 1327 | */ |
1328 | slack_bytes = (char *)resp->end - (char *)resp->p; | 1328 | slack_bytes = (char *)resp->end - (char *)resp->p; |
1329 | if (slack_bytes < COMPOUND_SLACK_SPACE | 1329 | if (slack_bytes < COMPOUND_SLACK_SPACE |
1330 | + COMPOUND_ERR_SLACK_SPACE) { | 1330 | + COMPOUND_ERR_SLACK_SPACE) { |
1331 | BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE); | 1331 | BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE); |
1332 | op->status = nfserr_resource; | 1332 | op->status = nfserr_resource; |
1333 | goto encode_op; | 1333 | goto encode_op; |
1334 | } | 1334 | } |
1335 | 1335 | ||
1336 | opdesc = OPDESC(op); | 1336 | opdesc = OPDESC(op); |
1337 | 1337 | ||
1338 | if (!cstate->current_fh.fh_dentry) { | 1338 | if (!cstate->current_fh.fh_dentry) { |
1339 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { | 1339 | if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { |
1340 | op->status = nfserr_nofilehandle; | 1340 | op->status = nfserr_nofilehandle; |
1341 | goto encode_op; | 1341 | goto encode_op; |
1342 | } | 1342 | } |
1343 | } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && | 1343 | } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && |
1344 | !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { | 1344 | !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { |
1345 | op->status = nfserr_moved; | 1345 | op->status = nfserr_moved; |
1346 | goto encode_op; | 1346 | goto encode_op; |
1347 | } | 1347 | } |
1348 | 1348 | ||
1349 | /* If op is non-idempotent */ | 1349 | /* If op is non-idempotent */ |
1350 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { | 1350 | if (opdesc->op_flags & OP_MODIFIES_SOMETHING) { |
1351 | plen = opdesc->op_rsize_bop(rqstp, op); | 1351 | plen = opdesc->op_rsize_bop(rqstp, op); |
1352 | op->status = nfsd4_check_resp_size(resp, plen); | 1352 | op->status = nfsd4_check_resp_size(resp, plen); |
1353 | } | 1353 | } |
1354 | 1354 | ||
1355 | if (op->status) | 1355 | if (op->status) |
1356 | goto encode_op; | 1356 | goto encode_op; |
1357 | 1357 | ||
1358 | if (opdesc->op_get_currentstateid) | 1358 | if (opdesc->op_get_currentstateid) |
1359 | opdesc->op_get_currentstateid(cstate, &op->u); | 1359 | opdesc->op_get_currentstateid(cstate, &op->u); |
1360 | op->status = opdesc->op_func(rqstp, cstate, &op->u); | 1360 | op->status = opdesc->op_func(rqstp, cstate, &op->u); |
1361 | 1361 | ||
1362 | if (!op->status) { | 1362 | if (!op->status) { |
1363 | if (opdesc->op_set_currentstateid) | 1363 | if (opdesc->op_set_currentstateid) |
1364 | opdesc->op_set_currentstateid(cstate, &op->u); | 1364 | opdesc->op_set_currentstateid(cstate, &op->u); |
1365 | 1365 | ||
1366 | if (opdesc->op_flags & OP_CLEAR_STATEID) | 1366 | if (opdesc->op_flags & OP_CLEAR_STATEID) |
1367 | clear_current_stateid(cstate); | 1367 | clear_current_stateid(cstate); |
1368 | 1368 | ||
1369 | if (need_wrongsec_check(rqstp)) | 1369 | if (need_wrongsec_check(rqstp)) |
1370 | op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp); | 1370 | op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp); |
1371 | } | 1371 | } |
1372 | 1372 | ||
1373 | encode_op: | 1373 | encode_op: |
1374 | /* Only from SEQUENCE */ | 1374 | /* Only from SEQUENCE */ |
1375 | if (resp->cstate.status == nfserr_replay_cache) { | 1375 | if (resp->cstate.status == nfserr_replay_cache) { |
1376 | dprintk("%s NFS4.1 replay from cache\n", __func__); | 1376 | dprintk("%s NFS4.1 replay from cache\n", __func__); |
1377 | status = op->status; | 1377 | status = op->status; |
1378 | goto out; | 1378 | goto out; |
1379 | } | 1379 | } |
1380 | if (op->status == nfserr_replay_me) { | 1380 | if (op->status == nfserr_replay_me) { |
1381 | op->replay = &cstate->replay_owner->so_replay; | 1381 | op->replay = &cstate->replay_owner->so_replay; |
1382 | nfsd4_encode_replay(resp, op); | 1382 | nfsd4_encode_replay(resp, op); |
1383 | status = op->status = op->replay->rp_status; | 1383 | status = op->status = op->replay->rp_status; |
1384 | } else { | 1384 | } else { |
1385 | nfsd4_encode_operation(resp, op); | 1385 | nfsd4_encode_operation(resp, op); |
1386 | status = op->status; | 1386 | status = op->status; |
1387 | } | 1387 | } |
1388 | 1388 | ||
1389 | dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n", | 1389 | dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n", |
1390 | args->ops, args->opcnt, resp->opcnt, op->opnum, | 1390 | args->ops, args->opcnt, resp->opcnt, op->opnum, |
1391 | be32_to_cpu(status)); | 1391 | be32_to_cpu(status)); |
1392 | 1392 | ||
1393 | if (cstate->replay_owner) { | 1393 | if (cstate->replay_owner) { |
1394 | nfs4_unlock_state(); | 1394 | nfs4_unlock_state(); |
1395 | cstate->replay_owner = NULL; | 1395 | cstate->replay_owner = NULL; |
1396 | } | 1396 | } |
1397 | /* XXX Ugh, we need to get rid of this kind of special case: */ | 1397 | /* XXX Ugh, we need to get rid of this kind of special case: */ |
1398 | if (op->opnum == OP_READ && op->u.read.rd_filp) | 1398 | if (op->opnum == OP_READ && op->u.read.rd_filp) |
1399 | fput(op->u.read.rd_filp); | 1399 | fput(op->u.read.rd_filp); |
1400 | 1400 | ||
1401 | nfsd4_increment_op_stats(op->opnum); | 1401 | nfsd4_increment_op_stats(op->opnum); |
1402 | } | 1402 | } |
1403 | 1403 | ||
1404 | resp->cstate.status = status; | 1404 | resp->cstate.status = status; |
1405 | fh_put(&resp->cstate.current_fh); | 1405 | fh_put(&resp->cstate.current_fh); |
1406 | fh_put(&resp->cstate.save_fh); | 1406 | fh_put(&resp->cstate.save_fh); |
1407 | BUG_ON(resp->cstate.replay_owner); | 1407 | BUG_ON(resp->cstate.replay_owner); |
1408 | out: | 1408 | out: |
1409 | /* Reset deferral mechanism for RPC deferrals */ | 1409 | /* Reset deferral mechanism for RPC deferrals */ |
1410 | rqstp->rq_usedeferral = 1; | 1410 | rqstp->rq_usedeferral = 1; |
1411 | dprintk("nfsv4 compound returned %d\n", ntohl(status)); | 1411 | dprintk("nfsv4 compound returned %d\n", ntohl(status)); |
1412 | return status; | 1412 | return status; |
1413 | } | 1413 | } |
1414 | 1414 | ||
1415 | #define op_encode_hdr_size (2) | 1415 | #define op_encode_hdr_size (2) |
1416 | #define op_encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE)) | 1416 | #define op_encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE)) |
1417 | #define op_encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE)) | 1417 | #define op_encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE)) |
1418 | #define op_encode_change_info_maxsz (5) | 1418 | #define op_encode_change_info_maxsz (5) |
1419 | #define nfs4_fattr_bitmap_maxsz (4) | 1419 | #define nfs4_fattr_bitmap_maxsz (4) |
1420 | 1420 | ||
1421 | #define op_encode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | 1421 | #define op_encode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) |
1422 | #define op_encode_lock_denied_maxsz (8 + op_encode_lockowner_maxsz) | 1422 | #define op_encode_lock_denied_maxsz (8 + op_encode_lockowner_maxsz) |
1423 | 1423 | ||
1424 | #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | 1424 | #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) |
1425 | 1425 | ||
1426 | #define op_encode_ace_maxsz (3 + nfs4_owner_maxsz) | 1426 | #define op_encode_ace_maxsz (3 + nfs4_owner_maxsz) |
1427 | #define op_encode_delegation_maxsz (1 + op_encode_stateid_maxsz + 1 + \ | 1427 | #define op_encode_delegation_maxsz (1 + op_encode_stateid_maxsz + 1 + \ |
1428 | op_encode_ace_maxsz) | 1428 | op_encode_ace_maxsz) |
1429 | 1429 | ||
1430 | #define op_encode_channel_attrs_maxsz (6 + 1 + 1) | 1430 | #define op_encode_channel_attrs_maxsz (6 + 1 + 1) |
1431 | 1431 | ||
1432 | static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1432 | static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1433 | { | 1433 | { |
1434 | return (op_encode_hdr_size) * sizeof(__be32); | 1434 | return (op_encode_hdr_size) * sizeof(__be32); |
1435 | } | 1435 | } |
1436 | 1436 | ||
1437 | static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1437 | static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1438 | { | 1438 | { |
1439 | return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32); | 1439 | return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32); |
1440 | } | 1440 | } |
1441 | 1441 | ||
1442 | static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1442 | static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1443 | { | 1443 | { |
1444 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); | 1444 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); |
1445 | } | 1445 | } |
1446 | 1446 | ||
1447 | static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1447 | static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1448 | { | 1448 | { |
1449 | return (op_encode_hdr_size + op_encode_change_info_maxsz | 1449 | return (op_encode_hdr_size + op_encode_change_info_maxsz |
1450 | + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); | 1450 | + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); |
1451 | } | 1451 | } |
1452 | 1452 | ||
1453 | static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1453 | static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1454 | { | 1454 | { |
1455 | return (op_encode_hdr_size + op_encode_change_info_maxsz) | 1455 | return (op_encode_hdr_size + op_encode_change_info_maxsz) |
1456 | * sizeof(__be32); | 1456 | * sizeof(__be32); |
1457 | } | 1457 | } |
1458 | 1458 | ||
1459 | static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1459 | static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1460 | { | 1460 | { |
1461 | return (op_encode_hdr_size + op_encode_lock_denied_maxsz) | 1461 | return (op_encode_hdr_size + op_encode_lock_denied_maxsz) |
1462 | * sizeof(__be32); | 1462 | * sizeof(__be32); |
1463 | } | 1463 | } |
1464 | 1464 | ||
1465 | static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1465 | static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1466 | { | 1466 | { |
1467 | return (op_encode_hdr_size + op_encode_stateid_maxsz | 1467 | return (op_encode_hdr_size + op_encode_stateid_maxsz |
1468 | + op_encode_change_info_maxsz + 1 | 1468 | + op_encode_change_info_maxsz + 1 |
1469 | + nfs4_fattr_bitmap_maxsz | 1469 | + nfs4_fattr_bitmap_maxsz |
1470 | + op_encode_delegation_maxsz) * sizeof(__be32); | 1470 | + op_encode_delegation_maxsz) * sizeof(__be32); |
1471 | } | 1471 | } |
1472 | 1472 | ||
1473 | static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1473 | static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1474 | { | 1474 | { |
1475 | u32 maxcount = 0, rlen = 0; | 1475 | u32 maxcount = 0, rlen = 0; |
1476 | 1476 | ||
1477 | maxcount = svc_max_payload(rqstp); | 1477 | maxcount = svc_max_payload(rqstp); |
1478 | rlen = op->u.read.rd_length; | 1478 | rlen = op->u.read.rd_length; |
1479 | 1479 | ||
1480 | if (rlen > maxcount) | 1480 | if (rlen > maxcount) |
1481 | rlen = maxcount; | 1481 | rlen = maxcount; |
1482 | 1482 | ||
1483 | return (op_encode_hdr_size + 2) * sizeof(__be32) + rlen; | 1483 | return (op_encode_hdr_size + 2) * sizeof(__be32) + rlen; |
1484 | } | 1484 | } |
1485 | 1485 | ||
1486 | static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1486 | static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1487 | { | 1487 | { |
1488 | u32 rlen = op->u.readdir.rd_maxcount; | 1488 | u32 rlen = op->u.readdir.rd_maxcount; |
1489 | 1489 | ||
1490 | if (rlen > PAGE_SIZE) | 1490 | if (rlen > PAGE_SIZE) |
1491 | rlen = PAGE_SIZE; | 1491 | rlen = PAGE_SIZE; |
1492 | 1492 | ||
1493 | return (op_encode_hdr_size + op_encode_verifier_maxsz) | 1493 | return (op_encode_hdr_size + op_encode_verifier_maxsz) |
1494 | * sizeof(__be32) + rlen; | 1494 | * sizeof(__be32) + rlen; |
1495 | } | 1495 | } |
1496 | 1496 | ||
1497 | static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1497 | static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1498 | { | 1498 | { |
1499 | return (op_encode_hdr_size + op_encode_change_info_maxsz) | 1499 | return (op_encode_hdr_size + op_encode_change_info_maxsz) |
1500 | * sizeof(__be32); | 1500 | * sizeof(__be32); |
1501 | } | 1501 | } |
1502 | 1502 | ||
1503 | static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1503 | static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1504 | { | 1504 | { |
1505 | return (op_encode_hdr_size + op_encode_change_info_maxsz | 1505 | return (op_encode_hdr_size + op_encode_change_info_maxsz |
1506 | + op_encode_change_info_maxsz) * sizeof(__be32); | 1506 | + op_encode_change_info_maxsz) * sizeof(__be32); |
1507 | } | 1507 | } |
1508 | 1508 | ||
1509 | static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1509 | static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1510 | { | 1510 | { |
1511 | return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); | 1511 | return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); |
1512 | } | 1512 | } |
1513 | 1513 | ||
1514 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1514 | static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1515 | { | 1515 | { |
1516 | return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32); | 1516 | return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32); |
1517 | } | 1517 | } |
1518 | 1518 | ||
1519 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1519 | static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1520 | { | 1520 | { |
1521 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); | 1521 | return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); |
1522 | } | 1522 | } |
1523 | 1523 | ||
1524 | static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1524 | static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1525 | { | 1525 | { |
1526 | return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ | 1526 | return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ |
1527 | 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\ | 1527 | 1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\ |
1528 | 2 + /*eir_server_owner.so_minor_id */\ | 1528 | 2 + /*eir_server_owner.so_minor_id */\ |
1529 | /* eir_server_owner.so_major_id<> */\ | 1529 | /* eir_server_owner.so_major_id<> */\ |
1530 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | 1530 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ |
1531 | /* eir_server_scope<> */\ | 1531 | /* eir_server_scope<> */\ |
1532 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ | 1532 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\ |
1533 | 1 + /* eir_server_impl_id array length */\ | 1533 | 1 + /* eir_server_impl_id array length */\ |
1534 | 0 /* ignored eir_server_impl_id contents */) * sizeof(__be32); | 1534 | 0 /* ignored eir_server_impl_id contents */) * sizeof(__be32); |
1535 | } | 1535 | } |
1536 | 1536 | ||
1537 | static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1537 | static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1538 | { | 1538 | { |
1539 | return (op_encode_hdr_size + \ | 1539 | return (op_encode_hdr_size + \ |
1540 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\ | 1540 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\ |
1541 | 2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32); | 1541 | 2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32); |
1542 | } | 1542 | } |
1543 | 1543 | ||
1544 | static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) | 1544 | static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) |
1545 | { | 1545 | { |
1546 | return (op_encode_hdr_size + \ | 1546 | return (op_encode_hdr_size + \ |
1547 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\ | 1547 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\ |
1548 | 2 + /* csr_sequence, csr_flags */\ | 1548 | 2 + /* csr_sequence, csr_flags */\ |
1549 | op_encode_channel_attrs_maxsz + \ | 1549 | op_encode_channel_attrs_maxsz + \ |
1550 | op_encode_channel_attrs_maxsz) * sizeof(__be32); | 1550 | op_encode_channel_attrs_maxsz) * sizeof(__be32); |
1551 | } | 1551 | } |
1552 | 1552 | ||
1553 | static struct nfsd4_operation nfsd4_ops[] = { | 1553 | static struct nfsd4_operation nfsd4_ops[] = { |
1554 | [OP_ACCESS] = { | 1554 | [OP_ACCESS] = { |
1555 | .op_func = (nfsd4op_func)nfsd4_access, | 1555 | .op_func = (nfsd4op_func)nfsd4_access, |
1556 | .op_name = "OP_ACCESS", | 1556 | .op_name = "OP_ACCESS", |
1557 | }, | 1557 | }, |
1558 | [OP_CLOSE] = { | 1558 | [OP_CLOSE] = { |
1559 | .op_func = (nfsd4op_func)nfsd4_close, | 1559 | .op_func = (nfsd4op_func)nfsd4_close, |
1560 | .op_flags = OP_MODIFIES_SOMETHING, | 1560 | .op_flags = OP_MODIFIES_SOMETHING, |
1561 | .op_name = "OP_CLOSE", | 1561 | .op_name = "OP_CLOSE", |
1562 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | 1562 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, |
1563 | .op_get_currentstateid = (stateid_getter)nfsd4_get_closestateid, | 1563 | .op_get_currentstateid = (stateid_getter)nfsd4_get_closestateid, |
1564 | .op_set_currentstateid = (stateid_setter)nfsd4_set_closestateid, | 1564 | .op_set_currentstateid = (stateid_setter)nfsd4_set_closestateid, |
1565 | }, | 1565 | }, |
1566 | [OP_COMMIT] = { | 1566 | [OP_COMMIT] = { |
1567 | .op_func = (nfsd4op_func)nfsd4_commit, | 1567 | .op_func = (nfsd4op_func)nfsd4_commit, |
1568 | .op_flags = OP_MODIFIES_SOMETHING, | 1568 | .op_flags = OP_MODIFIES_SOMETHING, |
1569 | .op_name = "OP_COMMIT", | 1569 | .op_name = "OP_COMMIT", |
1570 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_commit_rsize, | 1570 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_commit_rsize, |
1571 | }, | 1571 | }, |
1572 | [OP_CREATE] = { | 1572 | [OP_CREATE] = { |
1573 | .op_func = (nfsd4op_func)nfsd4_create, | 1573 | .op_func = (nfsd4op_func)nfsd4_create, |
1574 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID, | 1574 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID, |
1575 | .op_name = "OP_CREATE", | 1575 | .op_name = "OP_CREATE", |
1576 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize, | 1576 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_rsize, |
1577 | }, | 1577 | }, |
1578 | [OP_DELEGRETURN] = { | 1578 | [OP_DELEGRETURN] = { |
1579 | .op_func = (nfsd4op_func)nfsd4_delegreturn, | 1579 | .op_func = (nfsd4op_func)nfsd4_delegreturn, |
1580 | .op_flags = OP_MODIFIES_SOMETHING, | 1580 | .op_flags = OP_MODIFIES_SOMETHING, |
1581 | .op_name = "OP_DELEGRETURN", | 1581 | .op_name = "OP_DELEGRETURN", |
1582 | .op_rsize_bop = nfsd4_only_status_rsize, | 1582 | .op_rsize_bop = nfsd4_only_status_rsize, |
1583 | .op_get_currentstateid = (stateid_getter)nfsd4_get_delegreturnstateid, | 1583 | .op_get_currentstateid = (stateid_getter)nfsd4_get_delegreturnstateid, |
1584 | }, | 1584 | }, |
1585 | [OP_GETATTR] = { | 1585 | [OP_GETATTR] = { |
1586 | .op_func = (nfsd4op_func)nfsd4_getattr, | 1586 | .op_func = (nfsd4op_func)nfsd4_getattr, |
1587 | .op_flags = ALLOWED_ON_ABSENT_FS, | 1587 | .op_flags = ALLOWED_ON_ABSENT_FS, |
1588 | .op_name = "OP_GETATTR", | 1588 | .op_name = "OP_GETATTR", |
1589 | }, | 1589 | }, |
1590 | [OP_GETFH] = { | 1590 | [OP_GETFH] = { |
1591 | .op_func = (nfsd4op_func)nfsd4_getfh, | 1591 | .op_func = (nfsd4op_func)nfsd4_getfh, |
1592 | .op_name = "OP_GETFH", | 1592 | .op_name = "OP_GETFH", |
1593 | }, | 1593 | }, |
1594 | [OP_LINK] = { | 1594 | [OP_LINK] = { |
1595 | .op_func = (nfsd4op_func)nfsd4_link, | 1595 | .op_func = (nfsd4op_func)nfsd4_link, |
1596 | .op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING | 1596 | .op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING |
1597 | | OP_CACHEME, | 1597 | | OP_CACHEME, |
1598 | .op_name = "OP_LINK", | 1598 | .op_name = "OP_LINK", |
1599 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_link_rsize, | 1599 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_link_rsize, |
1600 | }, | 1600 | }, |
1601 | [OP_LOCK] = { | 1601 | [OP_LOCK] = { |
1602 | .op_func = (nfsd4op_func)nfsd4_lock, | 1602 | .op_func = (nfsd4op_func)nfsd4_lock, |
1603 | .op_flags = OP_MODIFIES_SOMETHING, | 1603 | .op_flags = OP_MODIFIES_SOMETHING, |
1604 | .op_name = "OP_LOCK", | 1604 | .op_name = "OP_LOCK", |
1605 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize, | 1605 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_lock_rsize, |
1606 | .op_set_currentstateid = (stateid_setter)nfsd4_set_lockstateid, | 1606 | .op_set_currentstateid = (stateid_setter)nfsd4_set_lockstateid, |
1607 | }, | 1607 | }, |
1608 | [OP_LOCKT] = { | 1608 | [OP_LOCKT] = { |
1609 | .op_func = (nfsd4op_func)nfsd4_lockt, | 1609 | .op_func = (nfsd4op_func)nfsd4_lockt, |
1610 | .op_name = "OP_LOCKT", | 1610 | .op_name = "OP_LOCKT", |
1611 | }, | 1611 | }, |
1612 | [OP_LOCKU] = { | 1612 | [OP_LOCKU] = { |
1613 | .op_func = (nfsd4op_func)nfsd4_locku, | 1613 | .op_func = (nfsd4op_func)nfsd4_locku, |
1614 | .op_flags = OP_MODIFIES_SOMETHING, | 1614 | .op_flags = OP_MODIFIES_SOMETHING, |
1615 | .op_name = "OP_LOCKU", | 1615 | .op_name = "OP_LOCKU", |
1616 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | 1616 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, |
1617 | .op_get_currentstateid = (stateid_getter)nfsd4_get_lockustateid, | 1617 | .op_get_currentstateid = (stateid_getter)nfsd4_get_lockustateid, |
1618 | }, | 1618 | }, |
1619 | [OP_LOOKUP] = { | 1619 | [OP_LOOKUP] = { |
1620 | .op_func = (nfsd4op_func)nfsd4_lookup, | 1620 | .op_func = (nfsd4op_func)nfsd4_lookup, |
1621 | .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID, | 1621 | .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID, |
1622 | .op_name = "OP_LOOKUP", | 1622 | .op_name = "OP_LOOKUP", |
1623 | }, | 1623 | }, |
1624 | [OP_LOOKUPP] = { | 1624 | [OP_LOOKUPP] = { |
1625 | .op_func = (nfsd4op_func)nfsd4_lookupp, | 1625 | .op_func = (nfsd4op_func)nfsd4_lookupp, |
1626 | .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID, | 1626 | .op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID, |
1627 | .op_name = "OP_LOOKUPP", | 1627 | .op_name = "OP_LOOKUPP", |
1628 | }, | 1628 | }, |
1629 | [OP_NVERIFY] = { | 1629 | [OP_NVERIFY] = { |
1630 | .op_func = (nfsd4op_func)nfsd4_nverify, | 1630 | .op_func = (nfsd4op_func)nfsd4_nverify, |
1631 | .op_name = "OP_NVERIFY", | 1631 | .op_name = "OP_NVERIFY", |
1632 | }, | 1632 | }, |
1633 | [OP_OPEN] = { | 1633 | [OP_OPEN] = { |
1634 | .op_func = (nfsd4op_func)nfsd4_open, | 1634 | .op_func = (nfsd4op_func)nfsd4_open, |
1635 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, | 1635 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1636 | .op_name = "OP_OPEN", | 1636 | .op_name = "OP_OPEN", |
1637 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize, | 1637 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_open_rsize, |
1638 | .op_set_currentstateid = (stateid_setter)nfsd4_set_openstateid, | 1638 | .op_set_currentstateid = (stateid_setter)nfsd4_set_openstateid, |
1639 | }, | 1639 | }, |
1640 | [OP_OPEN_CONFIRM] = { | 1640 | [OP_OPEN_CONFIRM] = { |
1641 | .op_func = (nfsd4op_func)nfsd4_open_confirm, | 1641 | .op_func = (nfsd4op_func)nfsd4_open_confirm, |
1642 | .op_flags = OP_MODIFIES_SOMETHING, | 1642 | .op_flags = OP_MODIFIES_SOMETHING, |
1643 | .op_name = "OP_OPEN_CONFIRM", | 1643 | .op_name = "OP_OPEN_CONFIRM", |
1644 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | 1644 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, |
1645 | }, | 1645 | }, |
1646 | [OP_OPEN_DOWNGRADE] = { | 1646 | [OP_OPEN_DOWNGRADE] = { |
1647 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, | 1647 | .op_func = (nfsd4op_func)nfsd4_open_downgrade, |
1648 | .op_flags = OP_MODIFIES_SOMETHING, | 1648 | .op_flags = OP_MODIFIES_SOMETHING, |
1649 | .op_name = "OP_OPEN_DOWNGRADE", | 1649 | .op_name = "OP_OPEN_DOWNGRADE", |
1650 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, | 1650 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_status_stateid_rsize, |
1651 | .op_get_currentstateid = (stateid_getter)nfsd4_get_opendowngradestateid, | 1651 | .op_get_currentstateid = (stateid_getter)nfsd4_get_opendowngradestateid, |
1652 | .op_set_currentstateid = (stateid_setter)nfsd4_set_opendowngradestateid, | 1652 | .op_set_currentstateid = (stateid_setter)nfsd4_set_opendowngradestateid, |
1653 | }, | 1653 | }, |
1654 | [OP_PUTFH] = { | 1654 | [OP_PUTFH] = { |
1655 | .op_func = (nfsd4op_func)nfsd4_putfh, | 1655 | .op_func = (nfsd4op_func)nfsd4_putfh, |
1656 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1656 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1657 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING | 1657 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING |
1658 | | OP_CLEAR_STATEID, | 1658 | | OP_CLEAR_STATEID, |
1659 | .op_name = "OP_PUTFH", | 1659 | .op_name = "OP_PUTFH", |
1660 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1660 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1661 | }, | 1661 | }, |
1662 | [OP_PUTPUBFH] = { | 1662 | [OP_PUTPUBFH] = { |
1663 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1663 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1664 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1664 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1665 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING | 1665 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING |
1666 | | OP_CLEAR_STATEID, | 1666 | | OP_CLEAR_STATEID, |
1667 | .op_name = "OP_PUTPUBFH", | 1667 | .op_name = "OP_PUTPUBFH", |
1668 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1668 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1669 | }, | 1669 | }, |
1670 | [OP_PUTROOTFH] = { | 1670 | [OP_PUTROOTFH] = { |
1671 | .op_func = (nfsd4op_func)nfsd4_putrootfh, | 1671 | .op_func = (nfsd4op_func)nfsd4_putrootfh, |
1672 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1672 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1673 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING | 1673 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING |
1674 | | OP_CLEAR_STATEID, | 1674 | | OP_CLEAR_STATEID, |
1675 | .op_name = "OP_PUTROOTFH", | 1675 | .op_name = "OP_PUTROOTFH", |
1676 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1676 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1677 | }, | 1677 | }, |
1678 | [OP_READ] = { | 1678 | [OP_READ] = { |
1679 | .op_func = (nfsd4op_func)nfsd4_read, | 1679 | .op_func = (nfsd4op_func)nfsd4_read, |
1680 | .op_flags = OP_MODIFIES_SOMETHING, | 1680 | .op_flags = OP_MODIFIES_SOMETHING, |
1681 | .op_name = "OP_READ", | 1681 | .op_name = "OP_READ", |
1682 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize, | 1682 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_read_rsize, |
1683 | .op_get_currentstateid = (stateid_getter)nfsd4_get_readstateid, | 1683 | .op_get_currentstateid = (stateid_getter)nfsd4_get_readstateid, |
1684 | }, | 1684 | }, |
1685 | [OP_READDIR] = { | 1685 | [OP_READDIR] = { |
1686 | .op_func = (nfsd4op_func)nfsd4_readdir, | 1686 | .op_func = (nfsd4op_func)nfsd4_readdir, |
1687 | .op_flags = OP_MODIFIES_SOMETHING, | 1687 | .op_flags = OP_MODIFIES_SOMETHING, |
1688 | .op_name = "OP_READDIR", | 1688 | .op_name = "OP_READDIR", |
1689 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_readdir_rsize, | 1689 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_readdir_rsize, |
1690 | }, | 1690 | }, |
1691 | [OP_READLINK] = { | 1691 | [OP_READLINK] = { |
1692 | .op_func = (nfsd4op_func)nfsd4_readlink, | 1692 | .op_func = (nfsd4op_func)nfsd4_readlink, |
1693 | .op_name = "OP_READLINK", | 1693 | .op_name = "OP_READLINK", |
1694 | }, | 1694 | }, |
1695 | [OP_REMOVE] = { | 1695 | [OP_REMOVE] = { |
1696 | .op_func = (nfsd4op_func)nfsd4_remove, | 1696 | .op_func = (nfsd4op_func)nfsd4_remove, |
1697 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | 1697 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1698 | .op_name = "OP_REMOVE", | 1698 | .op_name = "OP_REMOVE", |
1699 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_remove_rsize, | 1699 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_remove_rsize, |
1700 | }, | 1700 | }, |
1701 | [OP_RENAME] = { | 1701 | [OP_RENAME] = { |
1702 | .op_func = (nfsd4op_func)nfsd4_rename, | 1702 | .op_func = (nfsd4op_func)nfsd4_rename, |
1703 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | 1703 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1704 | .op_name = "OP_RENAME", | 1704 | .op_name = "OP_RENAME", |
1705 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_rename_rsize, | 1705 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_rename_rsize, |
1706 | }, | 1706 | }, |
1707 | [OP_RENEW] = { | 1707 | [OP_RENEW] = { |
1708 | .op_func = (nfsd4op_func)nfsd4_renew, | 1708 | .op_func = (nfsd4op_func)nfsd4_renew, |
1709 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1709 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1710 | | OP_MODIFIES_SOMETHING, | 1710 | | OP_MODIFIES_SOMETHING, |
1711 | .op_name = "OP_RENEW", | 1711 | .op_name = "OP_RENEW", |
1712 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1712 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1713 | 1713 | ||
1714 | }, | 1714 | }, |
1715 | [OP_RESTOREFH] = { | 1715 | [OP_RESTOREFH] = { |
1716 | .op_func = (nfsd4op_func)nfsd4_restorefh, | 1716 | .op_func = (nfsd4op_func)nfsd4_restorefh, |
1717 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1717 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1718 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, | 1718 | | OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING, |
1719 | .op_name = "OP_RESTOREFH", | 1719 | .op_name = "OP_RESTOREFH", |
1720 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1720 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1721 | }, | 1721 | }, |
1722 | [OP_SAVEFH] = { | 1722 | [OP_SAVEFH] = { |
1723 | .op_func = (nfsd4op_func)nfsd4_savefh, | 1723 | .op_func = (nfsd4op_func)nfsd4_savefh, |
1724 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, | 1724 | .op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING, |
1725 | .op_name = "OP_SAVEFH", | 1725 | .op_name = "OP_SAVEFH", |
1726 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1726 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1727 | }, | 1727 | }, |
1728 | [OP_SECINFO] = { | 1728 | [OP_SECINFO] = { |
1729 | .op_func = (nfsd4op_func)nfsd4_secinfo, | 1729 | .op_func = (nfsd4op_func)nfsd4_secinfo, |
1730 | .op_flags = OP_HANDLES_WRONGSEC, | 1730 | .op_flags = OP_HANDLES_WRONGSEC, |
1731 | .op_name = "OP_SECINFO", | 1731 | .op_name = "OP_SECINFO", |
1732 | }, | 1732 | }, |
1733 | [OP_SETATTR] = { | 1733 | [OP_SETATTR] = { |
1734 | .op_func = (nfsd4op_func)nfsd4_setattr, | 1734 | .op_func = (nfsd4op_func)nfsd4_setattr, |
1735 | .op_name = "OP_SETATTR", | 1735 | .op_name = "OP_SETATTR", |
1736 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | 1736 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1737 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize, | 1737 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setattr_rsize, |
1738 | .op_get_currentstateid = (stateid_getter)nfsd4_get_setattrstateid, | 1738 | .op_get_currentstateid = (stateid_getter)nfsd4_get_setattrstateid, |
1739 | }, | 1739 | }, |
1740 | [OP_SETCLIENTID] = { | 1740 | [OP_SETCLIENTID] = { |
1741 | .op_func = (nfsd4op_func)nfsd4_setclientid, | 1741 | .op_func = (nfsd4op_func)nfsd4_setclientid, |
1742 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1742 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1743 | | OP_MODIFIES_SOMETHING | OP_CACHEME, | 1743 | | OP_MODIFIES_SOMETHING | OP_CACHEME, |
1744 | .op_name = "OP_SETCLIENTID", | 1744 | .op_name = "OP_SETCLIENTID", |
1745 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setclientid_rsize, | 1745 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_setclientid_rsize, |
1746 | }, | 1746 | }, |
1747 | [OP_SETCLIENTID_CONFIRM] = { | 1747 | [OP_SETCLIENTID_CONFIRM] = { |
1748 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, | 1748 | .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, |
1749 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1749 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1750 | | OP_MODIFIES_SOMETHING | OP_CACHEME, | 1750 | | OP_MODIFIES_SOMETHING | OP_CACHEME, |
1751 | .op_name = "OP_SETCLIENTID_CONFIRM", | 1751 | .op_name = "OP_SETCLIENTID_CONFIRM", |
1752 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1752 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1753 | }, | 1753 | }, |
1754 | [OP_VERIFY] = { | 1754 | [OP_VERIFY] = { |
1755 | .op_func = (nfsd4op_func)nfsd4_verify, | 1755 | .op_func = (nfsd4op_func)nfsd4_verify, |
1756 | .op_name = "OP_VERIFY", | 1756 | .op_name = "OP_VERIFY", |
1757 | }, | 1757 | }, |
1758 | [OP_WRITE] = { | 1758 | [OP_WRITE] = { |
1759 | .op_func = (nfsd4op_func)nfsd4_write, | 1759 | .op_func = (nfsd4op_func)nfsd4_write, |
1760 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, | 1760 | .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, |
1761 | .op_name = "OP_WRITE", | 1761 | .op_name = "OP_WRITE", |
1762 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize, | 1762 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_write_rsize, |
1763 | .op_get_currentstateid = (stateid_getter)nfsd4_get_writestateid, | 1763 | .op_get_currentstateid = (stateid_getter)nfsd4_get_writestateid, |
1764 | }, | 1764 | }, |
1765 | [OP_RELEASE_LOCKOWNER] = { | 1765 | [OP_RELEASE_LOCKOWNER] = { |
1766 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, | 1766 | .op_func = (nfsd4op_func)nfsd4_release_lockowner, |
1767 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS | 1767 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS |
1768 | | OP_MODIFIES_SOMETHING, | 1768 | | OP_MODIFIES_SOMETHING, |
1769 | .op_name = "OP_RELEASE_LOCKOWNER", | 1769 | .op_name = "OP_RELEASE_LOCKOWNER", |
1770 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1770 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1771 | }, | 1771 | }, |
1772 | 1772 | ||
1773 | /* NFSv4.1 operations */ | 1773 | /* NFSv4.1 operations */ |
1774 | [OP_EXCHANGE_ID] = { | 1774 | [OP_EXCHANGE_ID] = { |
1775 | .op_func = (nfsd4op_func)nfsd4_exchange_id, | 1775 | .op_func = (nfsd4op_func)nfsd4_exchange_id, |
1776 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP | 1776 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1777 | | OP_MODIFIES_SOMETHING, | 1777 | | OP_MODIFIES_SOMETHING, |
1778 | .op_name = "OP_EXCHANGE_ID", | 1778 | .op_name = "OP_EXCHANGE_ID", |
1779 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, | 1779 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, |
1780 | }, | 1780 | }, |
1781 | [OP_BACKCHANNEL_CTL] = { | 1781 | [OP_BACKCHANNEL_CTL] = { |
1782 | .op_func = (nfsd4op_func)nfsd4_backchannel_ctl, | 1782 | .op_func = (nfsd4op_func)nfsd4_backchannel_ctl, |
1783 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, | 1783 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1784 | .op_name = "OP_BACKCHANNEL_CTL", | 1784 | .op_name = "OP_BACKCHANNEL_CTL", |
1785 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1785 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1786 | }, | 1786 | }, |
1787 | [OP_BIND_CONN_TO_SESSION] = { | 1787 | [OP_BIND_CONN_TO_SESSION] = { |
1788 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | 1788 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, |
1789 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP | 1789 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1790 | | OP_MODIFIES_SOMETHING, | 1790 | | OP_MODIFIES_SOMETHING, |
1791 | .op_name = "OP_BIND_CONN_TO_SESSION", | 1791 | .op_name = "OP_BIND_CONN_TO_SESSION", |
1792 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_bind_conn_to_session_rsize, | 1792 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_bind_conn_to_session_rsize, |
1793 | }, | 1793 | }, |
1794 | [OP_CREATE_SESSION] = { | 1794 | [OP_CREATE_SESSION] = { |
1795 | .op_func = (nfsd4op_func)nfsd4_create_session, | 1795 | .op_func = (nfsd4op_func)nfsd4_create_session, |
1796 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP | 1796 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1797 | | OP_MODIFIES_SOMETHING, | 1797 | | OP_MODIFIES_SOMETHING, |
1798 | .op_name = "OP_CREATE_SESSION", | 1798 | .op_name = "OP_CREATE_SESSION", |
1799 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_session_rsize, | 1799 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_create_session_rsize, |
1800 | }, | 1800 | }, |
1801 | [OP_DESTROY_SESSION] = { | 1801 | [OP_DESTROY_SESSION] = { |
1802 | .op_func = (nfsd4op_func)nfsd4_destroy_session, | 1802 | .op_func = (nfsd4op_func)nfsd4_destroy_session, |
1803 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP | 1803 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1804 | | OP_MODIFIES_SOMETHING, | 1804 | | OP_MODIFIES_SOMETHING, |
1805 | .op_name = "OP_DESTROY_SESSION", | 1805 | .op_name = "OP_DESTROY_SESSION", |
1806 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1806 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1807 | }, | 1807 | }, |
1808 | [OP_SEQUENCE] = { | 1808 | [OP_SEQUENCE] = { |
1809 | .op_func = (nfsd4op_func)nfsd4_sequence, | 1809 | .op_func = (nfsd4op_func)nfsd4_sequence, |
1810 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1810 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, |
1811 | .op_name = "OP_SEQUENCE", | 1811 | .op_name = "OP_SEQUENCE", |
1812 | }, | 1812 | }, |
1813 | [OP_DESTROY_CLIENTID] = { | 1813 | [OP_DESTROY_CLIENTID] = { |
1814 | .op_func = (nfsd4op_func)nfsd4_destroy_clientid, | 1814 | .op_func = (nfsd4op_func)nfsd4_destroy_clientid, |
1815 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP | 1815 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
1816 | | OP_MODIFIES_SOMETHING, | 1816 | | OP_MODIFIES_SOMETHING, |
1817 | .op_name = "OP_DESTROY_CLIENTID", | 1817 | .op_name = "OP_DESTROY_CLIENTID", |
1818 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1818 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1819 | }, | 1819 | }, |
1820 | [OP_RECLAIM_COMPLETE] = { | 1820 | [OP_RECLAIM_COMPLETE] = { |
1821 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, | 1821 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, |
1822 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, | 1822 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1823 | .op_name = "OP_RECLAIM_COMPLETE", | 1823 | .op_name = "OP_RECLAIM_COMPLETE", |
1824 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1824 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1825 | }, | 1825 | }, |
1826 | [OP_SECINFO_NO_NAME] = { | 1826 | [OP_SECINFO_NO_NAME] = { |
1827 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, | 1827 | .op_func = (nfsd4op_func)nfsd4_secinfo_no_name, |
1828 | .op_flags = OP_HANDLES_WRONGSEC, | 1828 | .op_flags = OP_HANDLES_WRONGSEC, |
1829 | .op_name = "OP_SECINFO_NO_NAME", | 1829 | .op_name = "OP_SECINFO_NO_NAME", |
1830 | }, | 1830 | }, |
1831 | [OP_TEST_STATEID] = { | 1831 | [OP_TEST_STATEID] = { |
1832 | .op_func = (nfsd4op_func)nfsd4_test_stateid, | 1832 | .op_func = (nfsd4op_func)nfsd4_test_stateid, |
1833 | .op_flags = ALLOWED_WITHOUT_FH, | 1833 | .op_flags = ALLOWED_WITHOUT_FH, |
1834 | .op_name = "OP_TEST_STATEID", | 1834 | .op_name = "OP_TEST_STATEID", |
1835 | }, | 1835 | }, |
1836 | [OP_FREE_STATEID] = { | 1836 | [OP_FREE_STATEID] = { |
1837 | .op_func = (nfsd4op_func)nfsd4_free_stateid, | 1837 | .op_func = (nfsd4op_func)nfsd4_free_stateid, |
1838 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, | 1838 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1839 | .op_name = "OP_FREE_STATEID", | 1839 | .op_name = "OP_FREE_STATEID", |
1840 | .op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid, | 1840 | .op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid, |
1841 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1841 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1842 | }, | 1842 | }, |
1843 | }; | 1843 | }; |
1844 | 1844 | ||
1845 | #ifdef NFSD_DEBUG | 1845 | #ifdef NFSD_DEBUG |
1846 | static const char *nfsd4_op_name(unsigned opnum) | 1846 | static const char *nfsd4_op_name(unsigned opnum) |
1847 | { | 1847 | { |
1848 | if (opnum < ARRAY_SIZE(nfsd4_ops)) | 1848 | if (opnum < ARRAY_SIZE(nfsd4_ops)) |
1849 | return nfsd4_ops[opnum].op_name; | 1849 | return nfsd4_ops[opnum].op_name; |
1850 | return "unknown_operation"; | 1850 | return "unknown_operation"; |
1851 | } | 1851 | } |
1852 | #endif | 1852 | #endif |
1853 | 1853 | ||
1854 | #define nfsd4_voidres nfsd4_voidargs | 1854 | #define nfsd4_voidres nfsd4_voidargs |
1855 | struct nfsd4_voidargs { int dummy; }; | 1855 | struct nfsd4_voidargs { int dummy; }; |
1856 | 1856 | ||
1857 | static struct svc_procedure nfsd_procedures4[2] = { | 1857 | static struct svc_procedure nfsd_procedures4[2] = { |
1858 | [NFSPROC4_NULL] = { | 1858 | [NFSPROC4_NULL] = { |
1859 | .pc_func = (svc_procfunc) nfsd4_proc_null, | 1859 | .pc_func = (svc_procfunc) nfsd4_proc_null, |
1860 | .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres, | 1860 | .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres, |
1861 | .pc_argsize = sizeof(struct nfsd4_voidargs), | 1861 | .pc_argsize = sizeof(struct nfsd4_voidargs), |
1862 | .pc_ressize = sizeof(struct nfsd4_voidres), | 1862 | .pc_ressize = sizeof(struct nfsd4_voidres), |
1863 | .pc_cachetype = RC_NOCACHE, | 1863 | .pc_cachetype = RC_NOCACHE, |
1864 | .pc_xdrressize = 1, | 1864 | .pc_xdrressize = 1, |
1865 | }, | 1865 | }, |
1866 | [NFSPROC4_COMPOUND] = { | 1866 | [NFSPROC4_COMPOUND] = { |
1867 | .pc_func = (svc_procfunc) nfsd4_proc_compound, | 1867 | .pc_func = (svc_procfunc) nfsd4_proc_compound, |
1868 | .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs, | 1868 | .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs, |
1869 | .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, | 1869 | .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, |
1870 | .pc_argsize = sizeof(struct nfsd4_compoundargs), | 1870 | .pc_argsize = sizeof(struct nfsd4_compoundargs), |
1871 | .pc_ressize = sizeof(struct nfsd4_compoundres), | 1871 | .pc_ressize = sizeof(struct nfsd4_compoundres), |
1872 | .pc_release = nfsd4_release_compoundargs, | 1872 | .pc_release = nfsd4_release_compoundargs, |
1873 | .pc_cachetype = RC_NOCACHE, | 1873 | .pc_cachetype = RC_NOCACHE, |
1874 | .pc_xdrressize = NFSD_BUFSIZE/4, | 1874 | .pc_xdrressize = NFSD_BUFSIZE/4, |
1875 | }, | 1875 | }, |
1876 | }; | 1876 | }; |
1877 | 1877 | ||
1878 | struct svc_version nfsd_version4 = { | 1878 | struct svc_version nfsd_version4 = { |
1879 | .vs_vers = 4, | 1879 | .vs_vers = 4, |
1880 | .vs_nproc = 2, | 1880 | .vs_nproc = 2, |
1881 | .vs_proc = nfsd_procedures4, | 1881 | .vs_proc = nfsd_procedures4, |
1882 | .vs_dispatch = nfsd_dispatch, | 1882 | .vs_dispatch = nfsd_dispatch, |
1883 | .vs_xdrsize = NFS4_SVC_XDRSIZE, | 1883 | .vs_xdrsize = NFS4_SVC_XDRSIZE, |
1884 | }; | 1884 | }; |
1885 | 1885 | ||
1886 | /* | 1886 | /* |
1887 | * Local variables: | 1887 | * Local variables: |
1888 | * c-basic-offset: 8 | 1888 | * c-basic-offset: 8 |
1889 | * End: | 1889 | * End: |
1890 | */ | 1890 | */ |
1891 | 1891 |
fs/nfsd/nfsd.h
1 | /* | 1 | /* |
2 | * Hodge-podge collection of knfsd-related stuff. | 2 | * Hodge-podge collection of knfsd-related stuff. |
3 | * I will sort this out later. | 3 | * I will sort this out later. |
4 | * | 4 | * |
5 | * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> | 5 | * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #ifndef LINUX_NFSD_NFSD_H | 8 | #ifndef LINUX_NFSD_NFSD_H |
9 | #define LINUX_NFSD_NFSD_H | 9 | #define LINUX_NFSD_NFSD_H |
10 | 10 | ||
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/mount.h> | 12 | #include <linux/mount.h> |
13 | 13 | ||
14 | #include <linux/nfs.h> | 14 | #include <linux/nfs.h> |
15 | #include <linux/nfs2.h> | 15 | #include <linux/nfs2.h> |
16 | #include <linux/nfs3.h> | 16 | #include <linux/nfs3.h> |
17 | #include <linux/nfs4.h> | 17 | #include <linux/nfs4.h> |
18 | #include <linux/sunrpc/msg_prot.h> | 18 | #include <linux/sunrpc/msg_prot.h> |
19 | 19 | ||
20 | #include <linux/nfsd/debug.h> | 20 | #include <linux/nfsd/debug.h> |
21 | #include <linux/nfsd/export.h> | 21 | #include <linux/nfsd/export.h> |
22 | #include <linux/nfsd/stats.h> | 22 | #include <linux/nfsd/stats.h> |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * nfsd version | 25 | * nfsd version |
26 | */ | 26 | */ |
27 | #define NFSD_SUPPORTED_MINOR_VERSION 2 | 27 | #define NFSD_SUPPORTED_MINOR_VERSION 2 |
28 | /* | 28 | /* |
29 | * Maximum blocksizes supported by daemon under various circumstances. | 29 | * Maximum blocksizes supported by daemon under various circumstances. |
30 | */ | 30 | */ |
31 | #define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD | 31 | #define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD |
32 | /* NFSv2 is limited by the protocol specification, see RFC 1094 */ | 32 | /* NFSv2 is limited by the protocol specification, see RFC 1094 */ |
33 | #define NFSSVC_MAXBLKSIZE_V2 (8*1024) | 33 | #define NFSSVC_MAXBLKSIZE_V2 (8*1024) |
34 | 34 | ||
35 | 35 | ||
36 | /* | 36 | /* |
37 | * Largest number of bytes we need to allocate for an NFS | 37 | * Largest number of bytes we need to allocate for an NFS |
38 | * call or reply. Used to control buffer sizes. We use | 38 | * call or reply. Used to control buffer sizes. We use |
39 | * the length of v3 WRITE, READDIR and READDIR replies | 39 | * the length of v3 WRITE, READDIR and READDIR replies |
40 | * which are an RPC header, up to 26 XDR units of reply | 40 | * which are an RPC header, up to 26 XDR units of reply |
41 | * data, and some page data. | 41 | * data, and some page data. |
42 | * | 42 | * |
43 | * Note that accuracy here doesn't matter too much as the | 43 | * Note that accuracy here doesn't matter too much as the |
44 | * size is rounded up to a page size when allocating space. | 44 | * size is rounded up to a page size when allocating space. |
45 | */ | 45 | */ |
46 | #define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) | 46 | #define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE) |
47 | 47 | ||
48 | struct readdir_cd { | 48 | struct readdir_cd { |
49 | __be32 err; /* 0, nfserr, or nfserr_eof */ | 49 | __be32 err; /* 0, nfserr, or nfserr_eof */ |
50 | }; | 50 | }; |
51 | 51 | ||
52 | 52 | ||
53 | extern struct svc_program nfsd_program; | 53 | extern struct svc_program nfsd_program; |
54 | extern struct svc_version nfsd_version2, nfsd_version3, | 54 | extern struct svc_version nfsd_version2, nfsd_version3, |
55 | nfsd_version4; | 55 | nfsd_version4; |
56 | extern u32 nfsd_supported_minorversion; | ||
57 | extern struct mutex nfsd_mutex; | 56 | extern struct mutex nfsd_mutex; |
58 | extern spinlock_t nfsd_drc_lock; | 57 | extern spinlock_t nfsd_drc_lock; |
59 | extern unsigned long nfsd_drc_max_mem; | 58 | extern unsigned long nfsd_drc_max_mem; |
60 | extern unsigned long nfsd_drc_mem_used; | 59 | extern unsigned long nfsd_drc_mem_used; |
61 | 60 | ||
62 | extern const struct seq_operations nfs_exports_op; | 61 | extern const struct seq_operations nfs_exports_op; |
63 | 62 | ||
64 | /* | 63 | /* |
65 | * Function prototypes. | 64 | * Function prototypes. |
66 | */ | 65 | */ |
67 | int nfsd_svc(int nrservs, struct net *net); | 66 | int nfsd_svc(int nrservs, struct net *net); |
68 | int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); | 67 | int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp); |
69 | 68 | ||
70 | int nfsd_nrthreads(struct net *); | 69 | int nfsd_nrthreads(struct net *); |
71 | int nfsd_nrpools(struct net *); | 70 | int nfsd_nrpools(struct net *); |
72 | int nfsd_get_nrthreads(int n, int *, struct net *); | 71 | int nfsd_get_nrthreads(int n, int *, struct net *); |
73 | int nfsd_set_nrthreads(int n, int *, struct net *); | 72 | int nfsd_set_nrthreads(int n, int *, struct net *); |
74 | int nfsd_pool_stats_open(struct inode *, struct file *); | 73 | int nfsd_pool_stats_open(struct inode *, struct file *); |
75 | int nfsd_pool_stats_release(struct inode *, struct file *); | 74 | int nfsd_pool_stats_release(struct inode *, struct file *); |
76 | 75 | ||
77 | void nfsd_destroy(struct net *net); | 76 | void nfsd_destroy(struct net *net); |
78 | 77 | ||
79 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 78 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
80 | #ifdef CONFIG_NFSD_V2_ACL | 79 | #ifdef CONFIG_NFSD_V2_ACL |
81 | extern struct svc_version nfsd_acl_version2; | 80 | extern struct svc_version nfsd_acl_version2; |
82 | #else | 81 | #else |
83 | #define nfsd_acl_version2 NULL | 82 | #define nfsd_acl_version2 NULL |
84 | #endif | 83 | #endif |
85 | #ifdef CONFIG_NFSD_V3_ACL | 84 | #ifdef CONFIG_NFSD_V3_ACL |
86 | extern struct svc_version nfsd_acl_version3; | 85 | extern struct svc_version nfsd_acl_version3; |
87 | #else | 86 | #else |
88 | #define nfsd_acl_version3 NULL | 87 | #define nfsd_acl_version3 NULL |
89 | #endif | 88 | #endif |
90 | #endif | 89 | #endif |
91 | 90 | ||
92 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; | 91 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; |
93 | int nfsd_vers(int vers, enum vers_op change); | 92 | int nfsd_vers(int vers, enum vers_op change); |
94 | int nfsd_minorversion(u32 minorversion, enum vers_op change); | 93 | int nfsd_minorversion(u32 minorversion, enum vers_op change); |
95 | void nfsd_reset_versions(void); | 94 | void nfsd_reset_versions(void); |
96 | int nfsd_create_serv(struct net *net); | 95 | int nfsd_create_serv(struct net *net); |
97 | 96 | ||
98 | extern int nfsd_max_blksize; | 97 | extern int nfsd_max_blksize; |
99 | 98 | ||
100 | static inline int nfsd_v4client(struct svc_rqst *rq) | 99 | static inline int nfsd_v4client(struct svc_rqst *rq) |
101 | { | 100 | { |
102 | return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4; | 101 | return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4; |
103 | } | 102 | } |
104 | 103 | ||
105 | /* | 104 | /* |
106 | * NFSv4 State | 105 | * NFSv4 State |
107 | */ | 106 | */ |
108 | #ifdef CONFIG_NFSD_V4 | 107 | #ifdef CONFIG_NFSD_V4 |
109 | extern unsigned long max_delegations; | 108 | extern unsigned long max_delegations; |
110 | void nfs4_state_init(void); | 109 | void nfs4_state_init(void); |
111 | int nfsd4_init_slabs(void); | 110 | int nfsd4_init_slabs(void); |
112 | void nfsd4_free_slabs(void); | 111 | void nfsd4_free_slabs(void); |
113 | int nfs4_state_start(void); | 112 | int nfs4_state_start(void); |
114 | int nfs4_state_start_net(struct net *net); | 113 | int nfs4_state_start_net(struct net *net); |
115 | void nfs4_state_shutdown(void); | 114 | void nfs4_state_shutdown(void); |
116 | void nfs4_state_shutdown_net(struct net *net); | 115 | void nfs4_state_shutdown_net(struct net *net); |
117 | void nfs4_reset_lease(time_t leasetime); | 116 | void nfs4_reset_lease(time_t leasetime); |
118 | int nfs4_reset_recoverydir(char *recdir); | 117 | int nfs4_reset_recoverydir(char *recdir); |
119 | char * nfs4_recoverydir(void); | 118 | char * nfs4_recoverydir(void); |
120 | #else | 119 | #else |
121 | static inline void nfs4_state_init(void) { } | 120 | static inline void nfs4_state_init(void) { } |
122 | static inline int nfsd4_init_slabs(void) { return 0; } | 121 | static inline int nfsd4_init_slabs(void) { return 0; } |
123 | static inline void nfsd4_free_slabs(void) { } | 122 | static inline void nfsd4_free_slabs(void) { } |
124 | static inline int nfs4_state_start(void) { return 0; } | 123 | static inline int nfs4_state_start(void) { return 0; } |
125 | static inline int nfs4_state_start_net(struct net *net) { return 0; } | 124 | static inline int nfs4_state_start_net(struct net *net) { return 0; } |
126 | static inline void nfs4_state_shutdown(void) { } | 125 | static inline void nfs4_state_shutdown(void) { } |
127 | static inline void nfs4_state_shutdown_net(struct net *net) { } | 126 | static inline void nfs4_state_shutdown_net(struct net *net) { } |
128 | static inline void nfs4_reset_lease(time_t leasetime) { } | 127 | static inline void nfs4_reset_lease(time_t leasetime) { } |
129 | static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } | 128 | static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } |
130 | static inline char * nfs4_recoverydir(void) {return NULL; } | 129 | static inline char * nfs4_recoverydir(void) {return NULL; } |
131 | #endif | 130 | #endif |
132 | 131 | ||
133 | /* | 132 | /* |
134 | * lockd binding | 133 | * lockd binding |
135 | */ | 134 | */ |
136 | void nfsd_lockd_init(void); | 135 | void nfsd_lockd_init(void); |
137 | void nfsd_lockd_shutdown(void); | 136 | void nfsd_lockd_shutdown(void); |
138 | 137 | ||
139 | 138 | ||
140 | /* | 139 | /* |
141 | * These macros provide pre-xdr'ed values for faster operation. | 140 | * These macros provide pre-xdr'ed values for faster operation. |
142 | */ | 141 | */ |
143 | #define nfs_ok cpu_to_be32(NFS_OK) | 142 | #define nfs_ok cpu_to_be32(NFS_OK) |
144 | #define nfserr_perm cpu_to_be32(NFSERR_PERM) | 143 | #define nfserr_perm cpu_to_be32(NFSERR_PERM) |
145 | #define nfserr_noent cpu_to_be32(NFSERR_NOENT) | 144 | #define nfserr_noent cpu_to_be32(NFSERR_NOENT) |
146 | #define nfserr_io cpu_to_be32(NFSERR_IO) | 145 | #define nfserr_io cpu_to_be32(NFSERR_IO) |
147 | #define nfserr_nxio cpu_to_be32(NFSERR_NXIO) | 146 | #define nfserr_nxio cpu_to_be32(NFSERR_NXIO) |
148 | #define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN) | 147 | #define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN) |
149 | #define nfserr_acces cpu_to_be32(NFSERR_ACCES) | 148 | #define nfserr_acces cpu_to_be32(NFSERR_ACCES) |
150 | #define nfserr_exist cpu_to_be32(NFSERR_EXIST) | 149 | #define nfserr_exist cpu_to_be32(NFSERR_EXIST) |
151 | #define nfserr_xdev cpu_to_be32(NFSERR_XDEV) | 150 | #define nfserr_xdev cpu_to_be32(NFSERR_XDEV) |
152 | #define nfserr_nodev cpu_to_be32(NFSERR_NODEV) | 151 | #define nfserr_nodev cpu_to_be32(NFSERR_NODEV) |
153 | #define nfserr_notdir cpu_to_be32(NFSERR_NOTDIR) | 152 | #define nfserr_notdir cpu_to_be32(NFSERR_NOTDIR) |
154 | #define nfserr_isdir cpu_to_be32(NFSERR_ISDIR) | 153 | #define nfserr_isdir cpu_to_be32(NFSERR_ISDIR) |
155 | #define nfserr_inval cpu_to_be32(NFSERR_INVAL) | 154 | #define nfserr_inval cpu_to_be32(NFSERR_INVAL) |
156 | #define nfserr_fbig cpu_to_be32(NFSERR_FBIG) | 155 | #define nfserr_fbig cpu_to_be32(NFSERR_FBIG) |
157 | #define nfserr_nospc cpu_to_be32(NFSERR_NOSPC) | 156 | #define nfserr_nospc cpu_to_be32(NFSERR_NOSPC) |
158 | #define nfserr_rofs cpu_to_be32(NFSERR_ROFS) | 157 | #define nfserr_rofs cpu_to_be32(NFSERR_ROFS) |
159 | #define nfserr_mlink cpu_to_be32(NFSERR_MLINK) | 158 | #define nfserr_mlink cpu_to_be32(NFSERR_MLINK) |
160 | #define nfserr_opnotsupp cpu_to_be32(NFSERR_OPNOTSUPP) | 159 | #define nfserr_opnotsupp cpu_to_be32(NFSERR_OPNOTSUPP) |
161 | #define nfserr_nametoolong cpu_to_be32(NFSERR_NAMETOOLONG) | 160 | #define nfserr_nametoolong cpu_to_be32(NFSERR_NAMETOOLONG) |
162 | #define nfserr_notempty cpu_to_be32(NFSERR_NOTEMPTY) | 161 | #define nfserr_notempty cpu_to_be32(NFSERR_NOTEMPTY) |
163 | #define nfserr_dquot cpu_to_be32(NFSERR_DQUOT) | 162 | #define nfserr_dquot cpu_to_be32(NFSERR_DQUOT) |
164 | #define nfserr_stale cpu_to_be32(NFSERR_STALE) | 163 | #define nfserr_stale cpu_to_be32(NFSERR_STALE) |
165 | #define nfserr_remote cpu_to_be32(NFSERR_REMOTE) | 164 | #define nfserr_remote cpu_to_be32(NFSERR_REMOTE) |
166 | #define nfserr_wflush cpu_to_be32(NFSERR_WFLUSH) | 165 | #define nfserr_wflush cpu_to_be32(NFSERR_WFLUSH) |
167 | #define nfserr_badhandle cpu_to_be32(NFSERR_BADHANDLE) | 166 | #define nfserr_badhandle cpu_to_be32(NFSERR_BADHANDLE) |
168 | #define nfserr_notsync cpu_to_be32(NFSERR_NOT_SYNC) | 167 | #define nfserr_notsync cpu_to_be32(NFSERR_NOT_SYNC) |
169 | #define nfserr_badcookie cpu_to_be32(NFSERR_BAD_COOKIE) | 168 | #define nfserr_badcookie cpu_to_be32(NFSERR_BAD_COOKIE) |
170 | #define nfserr_notsupp cpu_to_be32(NFSERR_NOTSUPP) | 169 | #define nfserr_notsupp cpu_to_be32(NFSERR_NOTSUPP) |
171 | #define nfserr_toosmall cpu_to_be32(NFSERR_TOOSMALL) | 170 | #define nfserr_toosmall cpu_to_be32(NFSERR_TOOSMALL) |
172 | #define nfserr_serverfault cpu_to_be32(NFSERR_SERVERFAULT) | 171 | #define nfserr_serverfault cpu_to_be32(NFSERR_SERVERFAULT) |
173 | #define nfserr_badtype cpu_to_be32(NFSERR_BADTYPE) | 172 | #define nfserr_badtype cpu_to_be32(NFSERR_BADTYPE) |
174 | #define nfserr_jukebox cpu_to_be32(NFSERR_JUKEBOX) | 173 | #define nfserr_jukebox cpu_to_be32(NFSERR_JUKEBOX) |
175 | #define nfserr_denied cpu_to_be32(NFSERR_DENIED) | 174 | #define nfserr_denied cpu_to_be32(NFSERR_DENIED) |
176 | #define nfserr_deadlock cpu_to_be32(NFSERR_DEADLOCK) | 175 | #define nfserr_deadlock cpu_to_be32(NFSERR_DEADLOCK) |
177 | #define nfserr_expired cpu_to_be32(NFSERR_EXPIRED) | 176 | #define nfserr_expired cpu_to_be32(NFSERR_EXPIRED) |
178 | #define nfserr_bad_cookie cpu_to_be32(NFSERR_BAD_COOKIE) | 177 | #define nfserr_bad_cookie cpu_to_be32(NFSERR_BAD_COOKIE) |
179 | #define nfserr_same cpu_to_be32(NFSERR_SAME) | 178 | #define nfserr_same cpu_to_be32(NFSERR_SAME) |
180 | #define nfserr_clid_inuse cpu_to_be32(NFSERR_CLID_INUSE) | 179 | #define nfserr_clid_inuse cpu_to_be32(NFSERR_CLID_INUSE) |
181 | #define nfserr_stale_clientid cpu_to_be32(NFSERR_STALE_CLIENTID) | 180 | #define nfserr_stale_clientid cpu_to_be32(NFSERR_STALE_CLIENTID) |
182 | #define nfserr_resource cpu_to_be32(NFSERR_RESOURCE) | 181 | #define nfserr_resource cpu_to_be32(NFSERR_RESOURCE) |
183 | #define nfserr_moved cpu_to_be32(NFSERR_MOVED) | 182 | #define nfserr_moved cpu_to_be32(NFSERR_MOVED) |
184 | #define nfserr_nofilehandle cpu_to_be32(NFSERR_NOFILEHANDLE) | 183 | #define nfserr_nofilehandle cpu_to_be32(NFSERR_NOFILEHANDLE) |
185 | #define nfserr_minor_vers_mismatch cpu_to_be32(NFSERR_MINOR_VERS_MISMATCH) | 184 | #define nfserr_minor_vers_mismatch cpu_to_be32(NFSERR_MINOR_VERS_MISMATCH) |
186 | #define nfserr_share_denied cpu_to_be32(NFSERR_SHARE_DENIED) | 185 | #define nfserr_share_denied cpu_to_be32(NFSERR_SHARE_DENIED) |
187 | #define nfserr_stale_stateid cpu_to_be32(NFSERR_STALE_STATEID) | 186 | #define nfserr_stale_stateid cpu_to_be32(NFSERR_STALE_STATEID) |
188 | #define nfserr_old_stateid cpu_to_be32(NFSERR_OLD_STATEID) | 187 | #define nfserr_old_stateid cpu_to_be32(NFSERR_OLD_STATEID) |
189 | #define nfserr_bad_stateid cpu_to_be32(NFSERR_BAD_STATEID) | 188 | #define nfserr_bad_stateid cpu_to_be32(NFSERR_BAD_STATEID) |
190 | #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) | 189 | #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) |
191 | #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) | 190 | #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) |
192 | #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) | 191 | #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) |
193 | #define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE) | 192 | #define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE) |
194 | #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) | 193 | #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) |
195 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) | 194 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) |
196 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) | 195 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) |
197 | #define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE) | 196 | #define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE) |
198 | #define nfserr_badowner cpu_to_be32(NFSERR_BADOWNER) | 197 | #define nfserr_badowner cpu_to_be32(NFSERR_BADOWNER) |
199 | #define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD) | 198 | #define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD) |
200 | #define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL) | 199 | #define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL) |
201 | #define nfserr_grace cpu_to_be32(NFSERR_GRACE) | 200 | #define nfserr_grace cpu_to_be32(NFSERR_GRACE) |
202 | #define nfserr_no_grace cpu_to_be32(NFSERR_NO_GRACE) | 201 | #define nfserr_no_grace cpu_to_be32(NFSERR_NO_GRACE) |
203 | #define nfserr_reclaim_bad cpu_to_be32(NFSERR_RECLAIM_BAD) | 202 | #define nfserr_reclaim_bad cpu_to_be32(NFSERR_RECLAIM_BAD) |
204 | #define nfserr_badname cpu_to_be32(NFSERR_BADNAME) | 203 | #define nfserr_badname cpu_to_be32(NFSERR_BADNAME) |
205 | #define nfserr_cb_path_down cpu_to_be32(NFSERR_CB_PATH_DOWN) | 204 | #define nfserr_cb_path_down cpu_to_be32(NFSERR_CB_PATH_DOWN) |
206 | #define nfserr_locked cpu_to_be32(NFSERR_LOCKED) | 205 | #define nfserr_locked cpu_to_be32(NFSERR_LOCKED) |
207 | #define nfserr_wrongsec cpu_to_be32(NFSERR_WRONGSEC) | 206 | #define nfserr_wrongsec cpu_to_be32(NFSERR_WRONGSEC) |
208 | #define nfserr_badiomode cpu_to_be32(NFS4ERR_BADIOMODE) | 207 | #define nfserr_badiomode cpu_to_be32(NFS4ERR_BADIOMODE) |
209 | #define nfserr_badlayout cpu_to_be32(NFS4ERR_BADLAYOUT) | 208 | #define nfserr_badlayout cpu_to_be32(NFS4ERR_BADLAYOUT) |
210 | #define nfserr_bad_session_digest cpu_to_be32(NFS4ERR_BAD_SESSION_DIGEST) | 209 | #define nfserr_bad_session_digest cpu_to_be32(NFS4ERR_BAD_SESSION_DIGEST) |
211 | #define nfserr_badsession cpu_to_be32(NFS4ERR_BADSESSION) | 210 | #define nfserr_badsession cpu_to_be32(NFS4ERR_BADSESSION) |
212 | #define nfserr_badslot cpu_to_be32(NFS4ERR_BADSLOT) | 211 | #define nfserr_badslot cpu_to_be32(NFS4ERR_BADSLOT) |
213 | #define nfserr_complete_already cpu_to_be32(NFS4ERR_COMPLETE_ALREADY) | 212 | #define nfserr_complete_already cpu_to_be32(NFS4ERR_COMPLETE_ALREADY) |
214 | #define nfserr_conn_not_bound_to_session cpu_to_be32(NFS4ERR_CONN_NOT_BOUND_TO_SESSION) | 213 | #define nfserr_conn_not_bound_to_session cpu_to_be32(NFS4ERR_CONN_NOT_BOUND_TO_SESSION) |
215 | #define nfserr_deleg_already_wanted cpu_to_be32(NFS4ERR_DELEG_ALREADY_WANTED) | 214 | #define nfserr_deleg_already_wanted cpu_to_be32(NFS4ERR_DELEG_ALREADY_WANTED) |
216 | #define nfserr_back_chan_busy cpu_to_be32(NFS4ERR_BACK_CHAN_BUSY) | 215 | #define nfserr_back_chan_busy cpu_to_be32(NFS4ERR_BACK_CHAN_BUSY) |
217 | #define nfserr_layouttrylater cpu_to_be32(NFS4ERR_LAYOUTTRYLATER) | 216 | #define nfserr_layouttrylater cpu_to_be32(NFS4ERR_LAYOUTTRYLATER) |
218 | #define nfserr_layoutunavailable cpu_to_be32(NFS4ERR_LAYOUTUNAVAILABLE) | 217 | #define nfserr_layoutunavailable cpu_to_be32(NFS4ERR_LAYOUTUNAVAILABLE) |
219 | #define nfserr_nomatching_layout cpu_to_be32(NFS4ERR_NOMATCHING_LAYOUT) | 218 | #define nfserr_nomatching_layout cpu_to_be32(NFS4ERR_NOMATCHING_LAYOUT) |
220 | #define nfserr_recallconflict cpu_to_be32(NFS4ERR_RECALLCONFLICT) | 219 | #define nfserr_recallconflict cpu_to_be32(NFS4ERR_RECALLCONFLICT) |
221 | #define nfserr_unknown_layouttype cpu_to_be32(NFS4ERR_UNKNOWN_LAYOUTTYPE) | 220 | #define nfserr_unknown_layouttype cpu_to_be32(NFS4ERR_UNKNOWN_LAYOUTTYPE) |
222 | #define nfserr_seq_misordered cpu_to_be32(NFS4ERR_SEQ_MISORDERED) | 221 | #define nfserr_seq_misordered cpu_to_be32(NFS4ERR_SEQ_MISORDERED) |
223 | #define nfserr_sequence_pos cpu_to_be32(NFS4ERR_SEQUENCE_POS) | 222 | #define nfserr_sequence_pos cpu_to_be32(NFS4ERR_SEQUENCE_POS) |
224 | #define nfserr_req_too_big cpu_to_be32(NFS4ERR_REQ_TOO_BIG) | 223 | #define nfserr_req_too_big cpu_to_be32(NFS4ERR_REQ_TOO_BIG) |
225 | #define nfserr_rep_too_big cpu_to_be32(NFS4ERR_REP_TOO_BIG) | 224 | #define nfserr_rep_too_big cpu_to_be32(NFS4ERR_REP_TOO_BIG) |
226 | #define nfserr_rep_too_big_to_cache cpu_to_be32(NFS4ERR_REP_TOO_BIG_TO_CACHE) | 225 | #define nfserr_rep_too_big_to_cache cpu_to_be32(NFS4ERR_REP_TOO_BIG_TO_CACHE) |
227 | #define nfserr_retry_uncached_rep cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP) | 226 | #define nfserr_retry_uncached_rep cpu_to_be32(NFS4ERR_RETRY_UNCACHED_REP) |
228 | #define nfserr_unsafe_compound cpu_to_be32(NFS4ERR_UNSAFE_COMPOUND) | 227 | #define nfserr_unsafe_compound cpu_to_be32(NFS4ERR_UNSAFE_COMPOUND) |
229 | #define nfserr_too_many_ops cpu_to_be32(NFS4ERR_TOO_MANY_OPS) | 228 | #define nfserr_too_many_ops cpu_to_be32(NFS4ERR_TOO_MANY_OPS) |
230 | #define nfserr_op_not_in_session cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION) | 229 | #define nfserr_op_not_in_session cpu_to_be32(NFS4ERR_OP_NOT_IN_SESSION) |
231 | #define nfserr_hash_alg_unsupp cpu_to_be32(NFS4ERR_HASH_ALG_UNSUPP) | 230 | #define nfserr_hash_alg_unsupp cpu_to_be32(NFS4ERR_HASH_ALG_UNSUPP) |
232 | #define nfserr_clientid_busy cpu_to_be32(NFS4ERR_CLIENTID_BUSY) | 231 | #define nfserr_clientid_busy cpu_to_be32(NFS4ERR_CLIENTID_BUSY) |
233 | #define nfserr_pnfs_io_hole cpu_to_be32(NFS4ERR_PNFS_IO_HOLE) | 232 | #define nfserr_pnfs_io_hole cpu_to_be32(NFS4ERR_PNFS_IO_HOLE) |
234 | #define nfserr_seq_false_retry cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY) | 233 | #define nfserr_seq_false_retry cpu_to_be32(NFS4ERR_SEQ_FALSE_RETRY) |
235 | #define nfserr_bad_high_slot cpu_to_be32(NFS4ERR_BAD_HIGH_SLOT) | 234 | #define nfserr_bad_high_slot cpu_to_be32(NFS4ERR_BAD_HIGH_SLOT) |
236 | #define nfserr_deadsession cpu_to_be32(NFS4ERR_DEADSESSION) | 235 | #define nfserr_deadsession cpu_to_be32(NFS4ERR_DEADSESSION) |
237 | #define nfserr_encr_alg_unsupp cpu_to_be32(NFS4ERR_ENCR_ALG_UNSUPP) | 236 | #define nfserr_encr_alg_unsupp cpu_to_be32(NFS4ERR_ENCR_ALG_UNSUPP) |
238 | #define nfserr_pnfs_no_layout cpu_to_be32(NFS4ERR_PNFS_NO_LAYOUT) | 237 | #define nfserr_pnfs_no_layout cpu_to_be32(NFS4ERR_PNFS_NO_LAYOUT) |
239 | #define nfserr_not_only_op cpu_to_be32(NFS4ERR_NOT_ONLY_OP) | 238 | #define nfserr_not_only_op cpu_to_be32(NFS4ERR_NOT_ONLY_OP) |
240 | #define nfserr_wrong_cred cpu_to_be32(NFS4ERR_WRONG_CRED) | 239 | #define nfserr_wrong_cred cpu_to_be32(NFS4ERR_WRONG_CRED) |
241 | #define nfserr_wrong_type cpu_to_be32(NFS4ERR_WRONG_TYPE) | 240 | #define nfserr_wrong_type cpu_to_be32(NFS4ERR_WRONG_TYPE) |
242 | #define nfserr_dirdeleg_unavail cpu_to_be32(NFS4ERR_DIRDELEG_UNAVAIL) | 241 | #define nfserr_dirdeleg_unavail cpu_to_be32(NFS4ERR_DIRDELEG_UNAVAIL) |
243 | #define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG) | 242 | #define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG) |
244 | #define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT) | 243 | #define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT) |
245 | #define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED) | 244 | #define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED) |
246 | #define nfserr_partner_notsupp cpu_to_be32(NFS4ERR_PARTNER_NOTSUPP) | 245 | #define nfserr_partner_notsupp cpu_to_be32(NFS4ERR_PARTNER_NOTSUPP) |
247 | #define nfserr_partner_no_auth cpu_to_be32(NFS4ERR_PARTNER_NO_AUTH) | 246 | #define nfserr_partner_no_auth cpu_to_be32(NFS4ERR_PARTNER_NO_AUTH) |
248 | #define nfserr_metadata_notsupp cpu_to_be32(NFS4ERR_METADATA_NOTSUPP) | 247 | #define nfserr_metadata_notsupp cpu_to_be32(NFS4ERR_METADATA_NOTSUPP) |
249 | #define nfserr_offload_denied cpu_to_be32(NFS4ERR_OFFLOAD_DENIED) | 248 | #define nfserr_offload_denied cpu_to_be32(NFS4ERR_OFFLOAD_DENIED) |
250 | #define nfserr_wrong_lfs cpu_to_be32(NFS4ERR_WRONG_LFS) | 249 | #define nfserr_wrong_lfs cpu_to_be32(NFS4ERR_WRONG_LFS) |
251 | #define nfserr_badlabel cpu_to_be32(NFS4ERR_BADLABEL) | 250 | #define nfserr_badlabel cpu_to_be32(NFS4ERR_BADLABEL) |
252 | 251 | ||
253 | /* error codes for internal use */ | 252 | /* error codes for internal use */ |
254 | /* if a request fails due to kmalloc failure, it gets dropped. | 253 | /* if a request fails due to kmalloc failure, it gets dropped. |
255 | * Client should resend eventually | 254 | * Client should resend eventually |
256 | */ | 255 | */ |
257 | #define nfserr_dropit cpu_to_be32(30000) | 256 | #define nfserr_dropit cpu_to_be32(30000) |
258 | /* end-of-file indicator in readdir */ | 257 | /* end-of-file indicator in readdir */ |
259 | #define nfserr_eof cpu_to_be32(30001) | 258 | #define nfserr_eof cpu_to_be32(30001) |
260 | /* replay detected */ | 259 | /* replay detected */ |
261 | #define nfserr_replay_me cpu_to_be32(11001) | 260 | #define nfserr_replay_me cpu_to_be32(11001) |
262 | /* nfs41 replay detected */ | 261 | /* nfs41 replay detected */ |
263 | #define nfserr_replay_cache cpu_to_be32(11002) | 262 | #define nfserr_replay_cache cpu_to_be32(11002) |
264 | 263 | ||
265 | /* Check for dir entries '.' and '..' */ | 264 | /* Check for dir entries '.' and '..' */ |
266 | #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) | 265 | #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) |
267 | 266 | ||
268 | #ifdef CONFIG_NFSD_V4 | 267 | #ifdef CONFIG_NFSD_V4 |
269 | 268 | ||
270 | /* before processing a COMPOUND operation, we have to check that there | 269 | /* before processing a COMPOUND operation, we have to check that there |
271 | * is enough space in the buffer for XDR encode to succeed. otherwise, | 270 | * is enough space in the buffer for XDR encode to succeed. otherwise, |
272 | * we might process an operation with side effects, and be unable to | 271 | * we might process an operation with side effects, and be unable to |
273 | * tell the client that the operation succeeded. | 272 | * tell the client that the operation succeeded. |
274 | * | 273 | * |
275 | * COMPOUND_SLACK_SPACE - this is the minimum bytes of buffer space | 274 | * COMPOUND_SLACK_SPACE - this is the minimum bytes of buffer space |
276 | * needed to encode an "ordinary" _successful_ operation. (GETATTR, | 275 | * needed to encode an "ordinary" _successful_ operation. (GETATTR, |
277 | * READ, READDIR, and READLINK have their own buffer checks.) if we | 276 | * READ, READDIR, and READLINK have their own buffer checks.) if we |
278 | * fall below this level, we fail the next operation with NFS4ERR_RESOURCE. | 277 | * fall below this level, we fail the next operation with NFS4ERR_RESOURCE. |
279 | * | 278 | * |
280 | * COMPOUND_ERR_SLACK_SPACE - this is the minimum bytes of buffer space | 279 | * COMPOUND_ERR_SLACK_SPACE - this is the minimum bytes of buffer space |
281 | * needed to encode an operation which has failed with NFS4ERR_RESOURCE. | 280 | * needed to encode an operation which has failed with NFS4ERR_RESOURCE. |
282 | * care is taken to ensure that we never fall below this level for any | 281 | * care is taken to ensure that we never fall below this level for any |
283 | * reason. | 282 | * reason. |
284 | */ | 283 | */ |
285 | #define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */ | 284 | #define COMPOUND_SLACK_SPACE 140 /* OP_GETFH */ |
286 | #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ | 285 | #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ |
287 | 286 | ||
288 | #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ | 287 | #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ |
289 | 288 | ||
290 | /* | 289 | /* |
291 | * The following attributes are currently not supported by the NFSv4 server: | 290 | * The following attributes are currently not supported by the NFSv4 server: |
292 | * ARCHIVE (deprecated anyway) | 291 | * ARCHIVE (deprecated anyway) |
293 | * HIDDEN (unlikely to be supported any time soon) | 292 | * HIDDEN (unlikely to be supported any time soon) |
294 | * MIMETYPE (unlikely to be supported any time soon) | 293 | * MIMETYPE (unlikely to be supported any time soon) |
295 | * QUOTA_* (will be supported in a forthcoming patch) | 294 | * QUOTA_* (will be supported in a forthcoming patch) |
296 | * SYSTEM (unlikely to be supported any time soon) | 295 | * SYSTEM (unlikely to be supported any time soon) |
297 | * TIME_BACKUP (unlikely to be supported any time soon) | 296 | * TIME_BACKUP (unlikely to be supported any time soon) |
298 | * TIME_CREATE (unlikely to be supported any time soon) | 297 | * TIME_CREATE (unlikely to be supported any time soon) |
299 | */ | 298 | */ |
300 | #define NFSD4_SUPPORTED_ATTRS_WORD0 \ | 299 | #define NFSD4_SUPPORTED_ATTRS_WORD0 \ |
301 | (FATTR4_WORD0_SUPPORTED_ATTRS | FATTR4_WORD0_TYPE | FATTR4_WORD0_FH_EXPIRE_TYPE \ | 300 | (FATTR4_WORD0_SUPPORTED_ATTRS | FATTR4_WORD0_TYPE | FATTR4_WORD0_FH_EXPIRE_TYPE \ |
302 | | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_LINK_SUPPORT \ | 301 | | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_LINK_SUPPORT \ |
303 | | FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR | FATTR4_WORD0_FSID \ | 302 | | FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR | FATTR4_WORD0_FSID \ |
304 | | FATTR4_WORD0_UNIQUE_HANDLES | FATTR4_WORD0_LEASE_TIME | FATTR4_WORD0_RDATTR_ERROR \ | 303 | | FATTR4_WORD0_UNIQUE_HANDLES | FATTR4_WORD0_LEASE_TIME | FATTR4_WORD0_RDATTR_ERROR \ |
305 | | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \ | 304 | | FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \ |
306 | | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \ | 305 | | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \ |
307 | | FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \ | 306 | | FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \ |
308 | | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \ | 307 | | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \ |
309 | | FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \ | 308 | | FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \ |
310 | | FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL) | 309 | | FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL) |
311 | 310 | ||
312 | #define NFSD4_SUPPORTED_ATTRS_WORD1 \ | 311 | #define NFSD4_SUPPORTED_ATTRS_WORD1 \ |
313 | (FATTR4_WORD1_MODE | FATTR4_WORD1_NO_TRUNC | FATTR4_WORD1_NUMLINKS \ | 312 | (FATTR4_WORD1_MODE | FATTR4_WORD1_NO_TRUNC | FATTR4_WORD1_NUMLINKS \ |
314 | | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \ | 313 | | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \ |
315 | | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \ | 314 | | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \ |
316 | | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \ | 315 | | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \ |
317 | | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ | 316 | | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ |
318 | | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) | 317 | | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) |
319 | 318 | ||
320 | #define NFSD4_SUPPORTED_ATTRS_WORD2 0 | 319 | #define NFSD4_SUPPORTED_ATTRS_WORD2 0 |
321 | 320 | ||
322 | #define NFSD4_1_SUPPORTED_ATTRS_WORD0 \ | 321 | #define NFSD4_1_SUPPORTED_ATTRS_WORD0 \ |
323 | NFSD4_SUPPORTED_ATTRS_WORD0 | 322 | NFSD4_SUPPORTED_ATTRS_WORD0 |
324 | 323 | ||
325 | #define NFSD4_1_SUPPORTED_ATTRS_WORD1 \ | 324 | #define NFSD4_1_SUPPORTED_ATTRS_WORD1 \ |
326 | NFSD4_SUPPORTED_ATTRS_WORD1 | 325 | NFSD4_SUPPORTED_ATTRS_WORD1 |
327 | 326 | ||
328 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ | 327 | #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ |
329 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) | 328 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) |
330 | 329 | ||
331 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | 330 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL |
332 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 \ | 331 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 \ |
333 | (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL) | 332 | (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL) |
334 | #else | 333 | #else |
335 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 0 | 334 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 0 |
336 | #endif | 335 | #endif |
337 | 336 | ||
338 | static inline u32 nfsd_suppattrs0(u32 minorversion) | 337 | static inline u32 nfsd_suppattrs0(u32 minorversion) |
339 | { | 338 | { |
340 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 | 339 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 |
341 | : NFSD4_SUPPORTED_ATTRS_WORD0; | 340 | : NFSD4_SUPPORTED_ATTRS_WORD0; |
342 | } | 341 | } |
343 | 342 | ||
344 | static inline u32 nfsd_suppattrs1(u32 minorversion) | 343 | static inline u32 nfsd_suppattrs1(u32 minorversion) |
345 | { | 344 | { |
346 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD1 | 345 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD1 |
347 | : NFSD4_SUPPORTED_ATTRS_WORD1; | 346 | : NFSD4_SUPPORTED_ATTRS_WORD1; |
348 | } | 347 | } |
349 | 348 | ||
350 | static inline u32 nfsd_suppattrs2(u32 minorversion) | 349 | static inline u32 nfsd_suppattrs2(u32 minorversion) |
351 | { | 350 | { |
352 | switch (minorversion) { | 351 | switch (minorversion) { |
353 | default: return NFSD4_2_SUPPORTED_ATTRS_WORD2; | 352 | default: return NFSD4_2_SUPPORTED_ATTRS_WORD2; |
354 | case 1: return NFSD4_1_SUPPORTED_ATTRS_WORD2; | 353 | case 1: return NFSD4_1_SUPPORTED_ATTRS_WORD2; |
355 | case 0: return NFSD4_SUPPORTED_ATTRS_WORD2; | 354 | case 0: return NFSD4_SUPPORTED_ATTRS_WORD2; |
356 | } | 355 | } |
357 | } | 356 | } |
358 | 357 | ||
359 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ | 358 | /* These will return ERR_INVAL if specified in GETATTR or READDIR. */ |
360 | #define NFSD_WRITEONLY_ATTRS_WORD1 \ | 359 | #define NFSD_WRITEONLY_ATTRS_WORD1 \ |
361 | (FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) | 360 | (FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) |
362 | 361 | ||
363 | /* These are the only attrs allowed in CREATE/OPEN/SETATTR. */ | 362 | /* These are the only attrs allowed in CREATE/OPEN/SETATTR. */ |
364 | #define NFSD_WRITEABLE_ATTRS_WORD0 \ | 363 | #define NFSD_WRITEABLE_ATTRS_WORD0 \ |
365 | (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL) | 364 | (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL) |
366 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ | 365 | #define NFSD_WRITEABLE_ATTRS_WORD1 \ |
367 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ | 366 | (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ |
368 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) | 367 | | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) |
369 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | 368 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL |
370 | #define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL | 369 | #define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL |
371 | #else | 370 | #else |
372 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 | 371 | #define NFSD_WRITEABLE_ATTRS_WORD2 0 |
373 | #endif | 372 | #endif |
374 | 373 | ||
375 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ | 374 | #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ |
376 | NFSD_WRITEABLE_ATTRS_WORD0 | 375 | NFSD_WRITEABLE_ATTRS_WORD0 |
377 | /* | 376 | /* |
378 | * we currently store the exclusive create verifier in the v_{a,m}time | 377 | * we currently store the exclusive create verifier in the v_{a,m}time |
379 | * attributes so the client can't set these at create time using EXCLUSIVE4_1 | 378 | * attributes so the client can't set these at create time using EXCLUSIVE4_1 |
380 | */ | 379 | */ |
381 | #define NFSD_SUPPATTR_EXCLCREAT_WORD1 \ | 380 | #define NFSD_SUPPATTR_EXCLCREAT_WORD1 \ |
382 | (NFSD_WRITEABLE_ATTRS_WORD1 & \ | 381 | (NFSD_WRITEABLE_ATTRS_WORD1 & \ |
383 | ~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)) | 382 | ~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)) |
384 | #define NFSD_SUPPATTR_EXCLCREAT_WORD2 \ | 383 | #define NFSD_SUPPATTR_EXCLCREAT_WORD2 \ |
385 | NFSD_WRITEABLE_ATTRS_WORD2 | 384 | NFSD_WRITEABLE_ATTRS_WORD2 |
386 | 385 | ||
387 | extern int nfsd4_is_junction(struct dentry *dentry); | 386 | extern int nfsd4_is_junction(struct dentry *dentry); |
388 | extern int register_cld_notifier(void); | 387 | extern int register_cld_notifier(void); |
389 | extern void unregister_cld_notifier(void); | 388 | extern void unregister_cld_notifier(void); |
390 | #else /* CONFIG_NFSD_V4 */ | 389 | #else /* CONFIG_NFSD_V4 */ |
391 | static inline int nfsd4_is_junction(struct dentry *dentry) | 390 | static inline int nfsd4_is_junction(struct dentry *dentry) |
392 | { | 391 | { |
393 | return 0; | 392 | return 0; |
394 | } | 393 | } |
395 | 394 | ||
396 | #define register_cld_notifier() 0 | 395 | #define register_cld_notifier() 0 |
397 | #define unregister_cld_notifier() do { } while(0) | 396 | #define unregister_cld_notifier() do { } while(0) |
398 | 397 | ||
399 | #endif /* CONFIG_NFSD_V4 */ | 398 | #endif /* CONFIG_NFSD_V4 */ |
400 | 399 | ||
401 | #endif /* LINUX_NFSD_NFSD_H */ | 400 | #endif /* LINUX_NFSD_NFSD_H */ |
402 | 401 |
fs/nfsd/nfssvc.c
1 | /* | 1 | /* |
2 | * Central processing for nfsd. | 2 | * Central processing for nfsd. |
3 | * | 3 | * |
4 | * Authors: Olaf Kirch (okir@monad.swb.de) | 4 | * Authors: Olaf Kirch (okir@monad.swb.de) |
5 | * | 5 | * |
6 | * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> | 6 | * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | #include <linux/freezer.h> | 10 | #include <linux/freezer.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/fs_struct.h> | 12 | #include <linux/fs_struct.h> |
13 | #include <linux/swap.h> | 13 | #include <linux/swap.h> |
14 | 14 | ||
15 | #include <linux/sunrpc/stats.h> | 15 | #include <linux/sunrpc/stats.h> |
16 | #include <linux/sunrpc/svcsock.h> | 16 | #include <linux/sunrpc/svcsock.h> |
17 | #include <linux/lockd/bind.h> | 17 | #include <linux/lockd/bind.h> |
18 | #include <linux/nfsacl.h> | 18 | #include <linux/nfsacl.h> |
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <net/net_namespace.h> | 20 | #include <net/net_namespace.h> |
21 | #include "nfsd.h" | 21 | #include "nfsd.h" |
22 | #include "cache.h" | 22 | #include "cache.h" |
23 | #include "vfs.h" | 23 | #include "vfs.h" |
24 | #include "netns.h" | 24 | #include "netns.h" |
25 | 25 | ||
26 | #define NFSDDBG_FACILITY NFSDDBG_SVC | 26 | #define NFSDDBG_FACILITY NFSDDBG_SVC |
27 | 27 | ||
28 | extern struct svc_program nfsd_program; | 28 | extern struct svc_program nfsd_program; |
29 | static int nfsd(void *vrqstp); | 29 | static int nfsd(void *vrqstp); |
30 | 30 | ||
31 | /* | 31 | /* |
32 | * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members | 32 | * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members |
33 | * of the svc_serv struct. In particular, ->sv_nrthreads but also to some | 33 | * of the svc_serv struct. In particular, ->sv_nrthreads but also to some |
34 | * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt | 34 | * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt |
35 | * | 35 | * |
36 | * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a | 36 | * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a |
37 | * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number | 37 | * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number |
38 | * of nfsd threads must exist and each must listed in ->sp_all_threads in each | 38 | * of nfsd threads must exist and each must listed in ->sp_all_threads in each |
39 | * entry of ->sv_pools[]. | 39 | * entry of ->sv_pools[]. |
40 | * | 40 | * |
41 | * Transitions of the thread count between zero and non-zero are of particular | 41 | * Transitions of the thread count between zero and non-zero are of particular |
42 | * interest since the svc_serv needs to be created and initialized at that | 42 | * interest since the svc_serv needs to be created and initialized at that |
43 | * point, or freed. | 43 | * point, or freed. |
44 | * | 44 | * |
45 | * Finally, the nfsd_mutex also protects some of the global variables that are | 45 | * Finally, the nfsd_mutex also protects some of the global variables that are |
46 | * accessed when nfsd starts and that are settable via the write_* routines in | 46 | * accessed when nfsd starts and that are settable via the write_* routines in |
47 | * nfsctl.c. In particular: | 47 | * nfsctl.c. In particular: |
48 | * | 48 | * |
49 | * user_recovery_dirname | 49 | * user_recovery_dirname |
50 | * user_lease_time | 50 | * user_lease_time |
51 | * nfsd_versions | 51 | * nfsd_versions |
52 | */ | 52 | */ |
53 | DEFINE_MUTEX(nfsd_mutex); | 53 | DEFINE_MUTEX(nfsd_mutex); |
54 | 54 | ||
55 | /* | 55 | /* |
56 | * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used. | 56 | * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used. |
57 | * nfsd_drc_max_pages limits the total amount of memory available for | 57 | * nfsd_drc_max_pages limits the total amount of memory available for |
58 | * version 4.1 DRC caches. | 58 | * version 4.1 DRC caches. |
59 | * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage. | 59 | * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage. |
60 | */ | 60 | */ |
61 | spinlock_t nfsd_drc_lock; | 61 | spinlock_t nfsd_drc_lock; |
62 | unsigned long nfsd_drc_max_mem; | 62 | unsigned long nfsd_drc_max_mem; |
63 | unsigned long nfsd_drc_mem_used; | 63 | unsigned long nfsd_drc_mem_used; |
64 | 64 | ||
65 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 65 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
66 | static struct svc_stat nfsd_acl_svcstats; | 66 | static struct svc_stat nfsd_acl_svcstats; |
67 | static struct svc_version * nfsd_acl_version[] = { | 67 | static struct svc_version * nfsd_acl_version[] = { |
68 | [2] = &nfsd_acl_version2, | 68 | [2] = &nfsd_acl_version2, |
69 | [3] = &nfsd_acl_version3, | 69 | [3] = &nfsd_acl_version3, |
70 | }; | 70 | }; |
71 | 71 | ||
72 | #define NFSD_ACL_MINVERS 2 | 72 | #define NFSD_ACL_MINVERS 2 |
73 | #define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version) | 73 | #define NFSD_ACL_NRVERS ARRAY_SIZE(nfsd_acl_version) |
74 | static struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS]; | 74 | static struct svc_version *nfsd_acl_versions[NFSD_ACL_NRVERS]; |
75 | 75 | ||
76 | static struct svc_program nfsd_acl_program = { | 76 | static struct svc_program nfsd_acl_program = { |
77 | .pg_prog = NFS_ACL_PROGRAM, | 77 | .pg_prog = NFS_ACL_PROGRAM, |
78 | .pg_nvers = NFSD_ACL_NRVERS, | 78 | .pg_nvers = NFSD_ACL_NRVERS, |
79 | .pg_vers = nfsd_acl_versions, | 79 | .pg_vers = nfsd_acl_versions, |
80 | .pg_name = "nfsacl", | 80 | .pg_name = "nfsacl", |
81 | .pg_class = "nfsd", | 81 | .pg_class = "nfsd", |
82 | .pg_stats = &nfsd_acl_svcstats, | 82 | .pg_stats = &nfsd_acl_svcstats, |
83 | .pg_authenticate = &svc_set_client, | 83 | .pg_authenticate = &svc_set_client, |
84 | }; | 84 | }; |
85 | 85 | ||
86 | static struct svc_stat nfsd_acl_svcstats = { | 86 | static struct svc_stat nfsd_acl_svcstats = { |
87 | .program = &nfsd_acl_program, | 87 | .program = &nfsd_acl_program, |
88 | }; | 88 | }; |
89 | #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ | 89 | #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ |
90 | 90 | ||
91 | static struct svc_version * nfsd_version[] = { | 91 | static struct svc_version * nfsd_version[] = { |
92 | [2] = &nfsd_version2, | 92 | [2] = &nfsd_version2, |
93 | #if defined(CONFIG_NFSD_V3) | 93 | #if defined(CONFIG_NFSD_V3) |
94 | [3] = &nfsd_version3, | 94 | [3] = &nfsd_version3, |
95 | #endif | 95 | #endif |
96 | #if defined(CONFIG_NFSD_V4) | 96 | #if defined(CONFIG_NFSD_V4) |
97 | [4] = &nfsd_version4, | 97 | [4] = &nfsd_version4, |
98 | #endif | 98 | #endif |
99 | }; | 99 | }; |
100 | 100 | ||
101 | #define NFSD_MINVERS 2 | 101 | #define NFSD_MINVERS 2 |
102 | #define NFSD_NRVERS ARRAY_SIZE(nfsd_version) | 102 | #define NFSD_NRVERS ARRAY_SIZE(nfsd_version) |
103 | static struct svc_version *nfsd_versions[NFSD_NRVERS]; | 103 | static struct svc_version *nfsd_versions[NFSD_NRVERS]; |
104 | 104 | ||
105 | struct svc_program nfsd_program = { | 105 | struct svc_program nfsd_program = { |
106 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 106 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
107 | .pg_next = &nfsd_acl_program, | 107 | .pg_next = &nfsd_acl_program, |
108 | #endif | 108 | #endif |
109 | .pg_prog = NFS_PROGRAM, /* program number */ | 109 | .pg_prog = NFS_PROGRAM, /* program number */ |
110 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ | 110 | .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ |
111 | .pg_vers = nfsd_versions, /* version table */ | 111 | .pg_vers = nfsd_versions, /* version table */ |
112 | .pg_name = "nfsd", /* program name */ | 112 | .pg_name = "nfsd", /* program name */ |
113 | .pg_class = "nfsd", /* authentication class */ | 113 | .pg_class = "nfsd", /* authentication class */ |
114 | .pg_stats = &nfsd_svcstats, /* version table */ | 114 | .pg_stats = &nfsd_svcstats, /* version table */ |
115 | .pg_authenticate = &svc_set_client, /* export authentication */ | 115 | .pg_authenticate = &svc_set_client, /* export authentication */ |
116 | 116 | ||
117 | }; | 117 | }; |
118 | 118 | ||
119 | u32 nfsd_supported_minorversion = 1; | 119 | static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = { |
120 | [0] = 1, | ||
121 | [1] = 1, | ||
122 | }; | ||
120 | 123 | ||
121 | int nfsd_vers(int vers, enum vers_op change) | 124 | int nfsd_vers(int vers, enum vers_op change) |
122 | { | 125 | { |
123 | if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) | 126 | if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS) |
124 | return 0; | 127 | return 0; |
125 | switch(change) { | 128 | switch(change) { |
126 | case NFSD_SET: | 129 | case NFSD_SET: |
127 | nfsd_versions[vers] = nfsd_version[vers]; | 130 | nfsd_versions[vers] = nfsd_version[vers]; |
128 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 131 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
129 | if (vers < NFSD_ACL_NRVERS) | 132 | if (vers < NFSD_ACL_NRVERS) |
130 | nfsd_acl_versions[vers] = nfsd_acl_version[vers]; | 133 | nfsd_acl_versions[vers] = nfsd_acl_version[vers]; |
131 | #endif | 134 | #endif |
132 | break; | 135 | break; |
133 | case NFSD_CLEAR: | 136 | case NFSD_CLEAR: |
134 | nfsd_versions[vers] = NULL; | 137 | nfsd_versions[vers] = NULL; |
135 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 138 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
136 | if (vers < NFSD_ACL_NRVERS) | 139 | if (vers < NFSD_ACL_NRVERS) |
137 | nfsd_acl_versions[vers] = NULL; | 140 | nfsd_acl_versions[vers] = NULL; |
138 | #endif | 141 | #endif |
139 | break; | 142 | break; |
140 | case NFSD_TEST: | 143 | case NFSD_TEST: |
141 | return nfsd_versions[vers] != NULL; | 144 | return nfsd_versions[vers] != NULL; |
142 | case NFSD_AVAIL: | 145 | case NFSD_AVAIL: |
143 | return nfsd_version[vers] != NULL; | 146 | return nfsd_version[vers] != NULL; |
144 | } | 147 | } |
145 | return 0; | 148 | return 0; |
146 | } | 149 | } |
147 | 150 | ||
148 | int nfsd_minorversion(u32 minorversion, enum vers_op change) | 151 | int nfsd_minorversion(u32 minorversion, enum vers_op change) |
149 | { | 152 | { |
150 | if (minorversion > NFSD_SUPPORTED_MINOR_VERSION) | 153 | if (minorversion > NFSD_SUPPORTED_MINOR_VERSION) |
151 | return -1; | 154 | return -1; |
152 | switch(change) { | 155 | switch(change) { |
153 | case NFSD_SET: | 156 | case NFSD_SET: |
154 | nfsd_supported_minorversion = minorversion; | 157 | nfsd_supported_minorversions[minorversion] = true; |
155 | break; | 158 | break; |
156 | case NFSD_CLEAR: | 159 | case NFSD_CLEAR: |
157 | if (minorversion == 0) | 160 | nfsd_supported_minorversions[minorversion] = false; |
158 | return -1; | ||
159 | nfsd_supported_minorversion = minorversion - 1; | ||
160 | break; | 161 | break; |
161 | case NFSD_TEST: | 162 | case NFSD_TEST: |
162 | return minorversion <= nfsd_supported_minorversion; | 163 | return nfsd_supported_minorversions[minorversion]; |
163 | case NFSD_AVAIL: | 164 | case NFSD_AVAIL: |
164 | return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; | 165 | return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; |
165 | } | 166 | } |
166 | return 0; | 167 | return 0; |
167 | } | 168 | } |
168 | 169 | ||
169 | /* | 170 | /* |
170 | * Maximum number of nfsd processes | 171 | * Maximum number of nfsd processes |
171 | */ | 172 | */ |
172 | #define NFSD_MAXSERVS 8192 | 173 | #define NFSD_MAXSERVS 8192 |
173 | 174 | ||
174 | int nfsd_nrthreads(struct net *net) | 175 | int nfsd_nrthreads(struct net *net) |
175 | { | 176 | { |
176 | int rv = 0; | 177 | int rv = 0; |
177 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 178 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
178 | 179 | ||
179 | mutex_lock(&nfsd_mutex); | 180 | mutex_lock(&nfsd_mutex); |
180 | if (nn->nfsd_serv) | 181 | if (nn->nfsd_serv) |
181 | rv = nn->nfsd_serv->sv_nrthreads; | 182 | rv = nn->nfsd_serv->sv_nrthreads; |
182 | mutex_unlock(&nfsd_mutex); | 183 | mutex_unlock(&nfsd_mutex); |
183 | return rv; | 184 | return rv; |
184 | } | 185 | } |
185 | 186 | ||
186 | static int nfsd_init_socks(struct net *net) | 187 | static int nfsd_init_socks(struct net *net) |
187 | { | 188 | { |
188 | int error; | 189 | int error; |
189 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 190 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
190 | 191 | ||
191 | if (!list_empty(&nn->nfsd_serv->sv_permsocks)) | 192 | if (!list_empty(&nn->nfsd_serv->sv_permsocks)) |
192 | return 0; | 193 | return 0; |
193 | 194 | ||
194 | error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT, | 195 | error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT, |
195 | SVC_SOCK_DEFAULTS); | 196 | SVC_SOCK_DEFAULTS); |
196 | if (error < 0) | 197 | if (error < 0) |
197 | return error; | 198 | return error; |
198 | 199 | ||
199 | error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT, | 200 | error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT, |
200 | SVC_SOCK_DEFAULTS); | 201 | SVC_SOCK_DEFAULTS); |
201 | if (error < 0) | 202 | if (error < 0) |
202 | return error; | 203 | return error; |
203 | 204 | ||
204 | return 0; | 205 | return 0; |
205 | } | 206 | } |
206 | 207 | ||
207 | static int nfsd_users = 0; | 208 | static int nfsd_users = 0; |
208 | 209 | ||
209 | static int nfsd_startup_generic(int nrservs) | 210 | static int nfsd_startup_generic(int nrservs) |
210 | { | 211 | { |
211 | int ret; | 212 | int ret; |
212 | 213 | ||
213 | if (nfsd_users++) | 214 | if (nfsd_users++) |
214 | return 0; | 215 | return 0; |
215 | 216 | ||
216 | /* | 217 | /* |
217 | * Readahead param cache - will no-op if it already exists. | 218 | * Readahead param cache - will no-op if it already exists. |
218 | * (Note therefore results will be suboptimal if number of | 219 | * (Note therefore results will be suboptimal if number of |
219 | * threads is modified after nfsd start.) | 220 | * threads is modified after nfsd start.) |
220 | */ | 221 | */ |
221 | ret = nfsd_racache_init(2*nrservs); | 222 | ret = nfsd_racache_init(2*nrservs); |
222 | if (ret) | 223 | if (ret) |
223 | return ret; | 224 | return ret; |
224 | ret = nfs4_state_start(); | 225 | ret = nfs4_state_start(); |
225 | if (ret) | 226 | if (ret) |
226 | goto out_racache; | 227 | goto out_racache; |
227 | return 0; | 228 | return 0; |
228 | 229 | ||
229 | out_racache: | 230 | out_racache: |
230 | nfsd_racache_shutdown(); | 231 | nfsd_racache_shutdown(); |
231 | return ret; | 232 | return ret; |
232 | } | 233 | } |
233 | 234 | ||
234 | static void nfsd_shutdown_generic(void) | 235 | static void nfsd_shutdown_generic(void) |
235 | { | 236 | { |
236 | if (--nfsd_users) | 237 | if (--nfsd_users) |
237 | return; | 238 | return; |
238 | 239 | ||
239 | nfs4_state_shutdown(); | 240 | nfs4_state_shutdown(); |
240 | nfsd_racache_shutdown(); | 241 | nfsd_racache_shutdown(); |
241 | } | 242 | } |
242 | 243 | ||
243 | static int nfsd_startup_net(int nrservs, struct net *net) | 244 | static int nfsd_startup_net(int nrservs, struct net *net) |
244 | { | 245 | { |
245 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 246 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
246 | int ret; | 247 | int ret; |
247 | 248 | ||
248 | if (nn->nfsd_net_up) | 249 | if (nn->nfsd_net_up) |
249 | return 0; | 250 | return 0; |
250 | 251 | ||
251 | ret = nfsd_startup_generic(nrservs); | 252 | ret = nfsd_startup_generic(nrservs); |
252 | if (ret) | 253 | if (ret) |
253 | return ret; | 254 | return ret; |
254 | ret = nfsd_init_socks(net); | 255 | ret = nfsd_init_socks(net); |
255 | if (ret) | 256 | if (ret) |
256 | goto out_socks; | 257 | goto out_socks; |
257 | ret = lockd_up(net); | 258 | ret = lockd_up(net); |
258 | if (ret) | 259 | if (ret) |
259 | goto out_socks; | 260 | goto out_socks; |
260 | ret = nfs4_state_start_net(net); | 261 | ret = nfs4_state_start_net(net); |
261 | if (ret) | 262 | if (ret) |
262 | goto out_lockd; | 263 | goto out_lockd; |
263 | 264 | ||
264 | nn->nfsd_net_up = true; | 265 | nn->nfsd_net_up = true; |
265 | return 0; | 266 | return 0; |
266 | 267 | ||
267 | out_lockd: | 268 | out_lockd: |
268 | lockd_down(net); | 269 | lockd_down(net); |
269 | out_socks: | 270 | out_socks: |
270 | nfsd_shutdown_generic(); | 271 | nfsd_shutdown_generic(); |
271 | return ret; | 272 | return ret; |
272 | } | 273 | } |
273 | 274 | ||
274 | static void nfsd_shutdown_net(struct net *net) | 275 | static void nfsd_shutdown_net(struct net *net) |
275 | { | 276 | { |
276 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 277 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
277 | 278 | ||
278 | nfs4_state_shutdown_net(net); | 279 | nfs4_state_shutdown_net(net); |
279 | lockd_down(net); | 280 | lockd_down(net); |
280 | nn->nfsd_net_up = false; | 281 | nn->nfsd_net_up = false; |
281 | nfsd_shutdown_generic(); | 282 | nfsd_shutdown_generic(); |
282 | } | 283 | } |
283 | 284 | ||
284 | static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | 285 | static void nfsd_last_thread(struct svc_serv *serv, struct net *net) |
285 | { | 286 | { |
286 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 287 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
287 | 288 | ||
288 | /* | 289 | /* |
289 | * write_ports can create the server without actually starting | 290 | * write_ports can create the server without actually starting |
290 | * any threads--if we get shut down before any threads are | 291 | * any threads--if we get shut down before any threads are |
291 | * started, then nfsd_last_thread will be run before any of this | 292 | * started, then nfsd_last_thread will be run before any of this |
292 | * other initialization has been done. | 293 | * other initialization has been done. |
293 | */ | 294 | */ |
294 | if (!nn->nfsd_net_up) | 295 | if (!nn->nfsd_net_up) |
295 | return; | 296 | return; |
296 | nfsd_shutdown_net(net); | 297 | nfsd_shutdown_net(net); |
297 | 298 | ||
298 | svc_rpcb_cleanup(serv, net); | 299 | svc_rpcb_cleanup(serv, net); |
299 | 300 | ||
300 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " | 301 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " |
301 | "cache\n"); | 302 | "cache\n"); |
302 | nfsd_export_flush(net); | 303 | nfsd_export_flush(net); |
303 | } | 304 | } |
304 | 305 | ||
305 | void nfsd_reset_versions(void) | 306 | void nfsd_reset_versions(void) |
306 | { | 307 | { |
307 | int found_one = 0; | 308 | int found_one = 0; |
308 | int i; | 309 | int i; |
309 | 310 | ||
310 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { | 311 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { |
311 | if (nfsd_program.pg_vers[i]) | 312 | if (nfsd_program.pg_vers[i]) |
312 | found_one = 1; | 313 | found_one = 1; |
313 | } | 314 | } |
314 | 315 | ||
315 | if (!found_one) { | 316 | if (!found_one) { |
316 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) | 317 | for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) |
317 | nfsd_program.pg_vers[i] = nfsd_version[i]; | 318 | nfsd_program.pg_vers[i] = nfsd_version[i]; |
318 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 319 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
319 | for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) | 320 | for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) |
320 | nfsd_acl_program.pg_vers[i] = | 321 | nfsd_acl_program.pg_vers[i] = |
321 | nfsd_acl_version[i]; | 322 | nfsd_acl_version[i]; |
322 | #endif | 323 | #endif |
323 | } | 324 | } |
324 | } | 325 | } |
325 | 326 | ||
326 | /* | 327 | /* |
327 | * Each session guarantees a negotiated per slot memory cache for replies | 328 | * Each session guarantees a negotiated per slot memory cache for replies |
328 | * which in turn consumes memory beyond the v2/v3/v4.0 server. A dedicated | 329 | * which in turn consumes memory beyond the v2/v3/v4.0 server. A dedicated |
329 | * NFSv4.1 server might want to use more memory for a DRC than a machine | 330 | * NFSv4.1 server might want to use more memory for a DRC than a machine |
330 | * with mutiple services. | 331 | * with mutiple services. |
331 | * | 332 | * |
332 | * Impose a hard limit on the number of pages for the DRC which varies | 333 | * Impose a hard limit on the number of pages for the DRC which varies |
333 | * according to the machines free pages. This is of course only a default. | 334 | * according to the machines free pages. This is of course only a default. |
334 | * | 335 | * |
335 | * For now this is a #defined shift which could be under admin control | 336 | * For now this is a #defined shift which could be under admin control |
336 | * in the future. | 337 | * in the future. |
337 | */ | 338 | */ |
338 | static void set_max_drc(void) | 339 | static void set_max_drc(void) |
339 | { | 340 | { |
340 | #define NFSD_DRC_SIZE_SHIFT 10 | 341 | #define NFSD_DRC_SIZE_SHIFT 10 |
341 | nfsd_drc_max_mem = (nr_free_buffer_pages() | 342 | nfsd_drc_max_mem = (nr_free_buffer_pages() |
342 | >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE; | 343 | >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE; |
343 | nfsd_drc_mem_used = 0; | 344 | nfsd_drc_mem_used = 0; |
344 | spin_lock_init(&nfsd_drc_lock); | 345 | spin_lock_init(&nfsd_drc_lock); |
345 | dprintk("%s nfsd_drc_max_mem %lu \n", __func__, nfsd_drc_max_mem); | 346 | dprintk("%s nfsd_drc_max_mem %lu \n", __func__, nfsd_drc_max_mem); |
346 | } | 347 | } |
347 | 348 | ||
348 | static int nfsd_get_default_max_blksize(void) | 349 | static int nfsd_get_default_max_blksize(void) |
349 | { | 350 | { |
350 | struct sysinfo i; | 351 | struct sysinfo i; |
351 | unsigned long long target; | 352 | unsigned long long target; |
352 | unsigned long ret; | 353 | unsigned long ret; |
353 | 354 | ||
354 | si_meminfo(&i); | 355 | si_meminfo(&i); |
355 | target = (i.totalram - i.totalhigh) << PAGE_SHIFT; | 356 | target = (i.totalram - i.totalhigh) << PAGE_SHIFT; |
356 | /* | 357 | /* |
357 | * Aim for 1/4096 of memory per thread This gives 1MB on 4Gig | 358 | * Aim for 1/4096 of memory per thread This gives 1MB on 4Gig |
358 | * machines, but only uses 32K on 128M machines. Bottom out at | 359 | * machines, but only uses 32K on 128M machines. Bottom out at |
359 | * 8K on 32M and smaller. Of course, this is only a default. | 360 | * 8K on 32M and smaller. Of course, this is only a default. |
360 | */ | 361 | */ |
361 | target >>= 12; | 362 | target >>= 12; |
362 | 363 | ||
363 | ret = NFSSVC_MAXBLKSIZE; | 364 | ret = NFSSVC_MAXBLKSIZE; |
364 | while (ret > target && ret >= 8*1024*2) | 365 | while (ret > target && ret >= 8*1024*2) |
365 | ret /= 2; | 366 | ret /= 2; |
366 | return ret; | 367 | return ret; |
367 | } | 368 | } |
368 | 369 | ||
369 | int nfsd_create_serv(struct net *net) | 370 | int nfsd_create_serv(struct net *net) |
370 | { | 371 | { |
371 | int error; | 372 | int error; |
372 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 373 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
373 | 374 | ||
374 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 375 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
375 | if (nn->nfsd_serv) { | 376 | if (nn->nfsd_serv) { |
376 | svc_get(nn->nfsd_serv); | 377 | svc_get(nn->nfsd_serv); |
377 | return 0; | 378 | return 0; |
378 | } | 379 | } |
379 | if (nfsd_max_blksize == 0) | 380 | if (nfsd_max_blksize == 0) |
380 | nfsd_max_blksize = nfsd_get_default_max_blksize(); | 381 | nfsd_max_blksize = nfsd_get_default_max_blksize(); |
381 | nfsd_reset_versions(); | 382 | nfsd_reset_versions(); |
382 | nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, | 383 | nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, |
383 | nfsd_last_thread, nfsd, THIS_MODULE); | 384 | nfsd_last_thread, nfsd, THIS_MODULE); |
384 | if (nn->nfsd_serv == NULL) | 385 | if (nn->nfsd_serv == NULL) |
385 | return -ENOMEM; | 386 | return -ENOMEM; |
386 | 387 | ||
387 | error = svc_bind(nn->nfsd_serv, net); | 388 | error = svc_bind(nn->nfsd_serv, net); |
388 | if (error < 0) { | 389 | if (error < 0) { |
389 | svc_destroy(nn->nfsd_serv); | 390 | svc_destroy(nn->nfsd_serv); |
390 | return error; | 391 | return error; |
391 | } | 392 | } |
392 | 393 | ||
393 | set_max_drc(); | 394 | set_max_drc(); |
394 | do_gettimeofday(&nn->nfssvc_boot); /* record boot time */ | 395 | do_gettimeofday(&nn->nfssvc_boot); /* record boot time */ |
395 | return 0; | 396 | return 0; |
396 | } | 397 | } |
397 | 398 | ||
398 | int nfsd_nrpools(struct net *net) | 399 | int nfsd_nrpools(struct net *net) |
399 | { | 400 | { |
400 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 401 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
401 | 402 | ||
402 | if (nn->nfsd_serv == NULL) | 403 | if (nn->nfsd_serv == NULL) |
403 | return 0; | 404 | return 0; |
404 | else | 405 | else |
405 | return nn->nfsd_serv->sv_nrpools; | 406 | return nn->nfsd_serv->sv_nrpools; |
406 | } | 407 | } |
407 | 408 | ||
408 | int nfsd_get_nrthreads(int n, int *nthreads, struct net *net) | 409 | int nfsd_get_nrthreads(int n, int *nthreads, struct net *net) |
409 | { | 410 | { |
410 | int i = 0; | 411 | int i = 0; |
411 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 412 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
412 | 413 | ||
413 | if (nn->nfsd_serv != NULL) { | 414 | if (nn->nfsd_serv != NULL) { |
414 | for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++) | 415 | for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++) |
415 | nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads; | 416 | nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads; |
416 | } | 417 | } |
417 | 418 | ||
418 | return 0; | 419 | return 0; |
419 | } | 420 | } |
420 | 421 | ||
421 | void nfsd_destroy(struct net *net) | 422 | void nfsd_destroy(struct net *net) |
422 | { | 423 | { |
423 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 424 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
424 | int destroy = (nn->nfsd_serv->sv_nrthreads == 1); | 425 | int destroy = (nn->nfsd_serv->sv_nrthreads == 1); |
425 | 426 | ||
426 | if (destroy) | 427 | if (destroy) |
427 | svc_shutdown_net(nn->nfsd_serv, net); | 428 | svc_shutdown_net(nn->nfsd_serv, net); |
428 | svc_destroy(nn->nfsd_serv); | 429 | svc_destroy(nn->nfsd_serv); |
429 | if (destroy) | 430 | if (destroy) |
430 | nn->nfsd_serv = NULL; | 431 | nn->nfsd_serv = NULL; |
431 | } | 432 | } |
432 | 433 | ||
433 | int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) | 434 | int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) |
434 | { | 435 | { |
435 | int i = 0; | 436 | int i = 0; |
436 | int tot = 0; | 437 | int tot = 0; |
437 | int err = 0; | 438 | int err = 0; |
438 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 439 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
439 | 440 | ||
440 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); | 441 | WARN_ON(!mutex_is_locked(&nfsd_mutex)); |
441 | 442 | ||
442 | if (nn->nfsd_serv == NULL || n <= 0) | 443 | if (nn->nfsd_serv == NULL || n <= 0) |
443 | return 0; | 444 | return 0; |
444 | 445 | ||
445 | if (n > nn->nfsd_serv->sv_nrpools) | 446 | if (n > nn->nfsd_serv->sv_nrpools) |
446 | n = nn->nfsd_serv->sv_nrpools; | 447 | n = nn->nfsd_serv->sv_nrpools; |
447 | 448 | ||
448 | /* enforce a global maximum number of threads */ | 449 | /* enforce a global maximum number of threads */ |
449 | tot = 0; | 450 | tot = 0; |
450 | for (i = 0; i < n; i++) { | 451 | for (i = 0; i < n; i++) { |
451 | if (nthreads[i] > NFSD_MAXSERVS) | 452 | if (nthreads[i] > NFSD_MAXSERVS) |
452 | nthreads[i] = NFSD_MAXSERVS; | 453 | nthreads[i] = NFSD_MAXSERVS; |
453 | tot += nthreads[i]; | 454 | tot += nthreads[i]; |
454 | } | 455 | } |
455 | if (tot > NFSD_MAXSERVS) { | 456 | if (tot > NFSD_MAXSERVS) { |
456 | /* total too large: scale down requested numbers */ | 457 | /* total too large: scale down requested numbers */ |
457 | for (i = 0; i < n && tot > 0; i++) { | 458 | for (i = 0; i < n && tot > 0; i++) { |
458 | int new = nthreads[i] * NFSD_MAXSERVS / tot; | 459 | int new = nthreads[i] * NFSD_MAXSERVS / tot; |
459 | tot -= (nthreads[i] - new); | 460 | tot -= (nthreads[i] - new); |
460 | nthreads[i] = new; | 461 | nthreads[i] = new; |
461 | } | 462 | } |
462 | for (i = 0; i < n && tot > 0; i++) { | 463 | for (i = 0; i < n && tot > 0; i++) { |
463 | nthreads[i]--; | 464 | nthreads[i]--; |
464 | tot--; | 465 | tot--; |
465 | } | 466 | } |
466 | } | 467 | } |
467 | 468 | ||
468 | /* | 469 | /* |
469 | * There must always be a thread in pool 0; the admin | 470 | * There must always be a thread in pool 0; the admin |
470 | * can't shut down NFS completely using pool_threads. | 471 | * can't shut down NFS completely using pool_threads. |
471 | */ | 472 | */ |
472 | if (nthreads[0] == 0) | 473 | if (nthreads[0] == 0) |
473 | nthreads[0] = 1; | 474 | nthreads[0] = 1; |
474 | 475 | ||
475 | /* apply the new numbers */ | 476 | /* apply the new numbers */ |
476 | svc_get(nn->nfsd_serv); | 477 | svc_get(nn->nfsd_serv); |
477 | for (i = 0; i < n; i++) { | 478 | for (i = 0; i < n; i++) { |
478 | err = svc_set_num_threads(nn->nfsd_serv, &nn->nfsd_serv->sv_pools[i], | 479 | err = svc_set_num_threads(nn->nfsd_serv, &nn->nfsd_serv->sv_pools[i], |
479 | nthreads[i]); | 480 | nthreads[i]); |
480 | if (err) | 481 | if (err) |
481 | break; | 482 | break; |
482 | } | 483 | } |
483 | nfsd_destroy(net); | 484 | nfsd_destroy(net); |
484 | return err; | 485 | return err; |
485 | } | 486 | } |
486 | 487 | ||
487 | /* | 488 | /* |
488 | * Adjust the number of threads and return the new number of threads. | 489 | * Adjust the number of threads and return the new number of threads. |
489 | * This is also the function that starts the server if necessary, if | 490 | * This is also the function that starts the server if necessary, if |
490 | * this is the first time nrservs is nonzero. | 491 | * this is the first time nrservs is nonzero. |
491 | */ | 492 | */ |
492 | int | 493 | int |
493 | nfsd_svc(int nrservs, struct net *net) | 494 | nfsd_svc(int nrservs, struct net *net) |
494 | { | 495 | { |
495 | int error; | 496 | int error; |
496 | bool nfsd_up_before; | 497 | bool nfsd_up_before; |
497 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 498 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
498 | 499 | ||
499 | mutex_lock(&nfsd_mutex); | 500 | mutex_lock(&nfsd_mutex); |
500 | dprintk("nfsd: creating service\n"); | 501 | dprintk("nfsd: creating service\n"); |
501 | if (nrservs <= 0) | 502 | if (nrservs <= 0) |
502 | nrservs = 0; | 503 | nrservs = 0; |
503 | if (nrservs > NFSD_MAXSERVS) | 504 | if (nrservs > NFSD_MAXSERVS) |
504 | nrservs = NFSD_MAXSERVS; | 505 | nrservs = NFSD_MAXSERVS; |
505 | error = 0; | 506 | error = 0; |
506 | if (nrservs == 0 && nn->nfsd_serv == NULL) | 507 | if (nrservs == 0 && nn->nfsd_serv == NULL) |
507 | goto out; | 508 | goto out; |
508 | 509 | ||
509 | error = nfsd_create_serv(net); | 510 | error = nfsd_create_serv(net); |
510 | if (error) | 511 | if (error) |
511 | goto out; | 512 | goto out; |
512 | 513 | ||
513 | nfsd_up_before = nn->nfsd_net_up; | 514 | nfsd_up_before = nn->nfsd_net_up; |
514 | 515 | ||
515 | error = nfsd_startup_net(nrservs, net); | 516 | error = nfsd_startup_net(nrservs, net); |
516 | if (error) | 517 | if (error) |
517 | goto out_destroy; | 518 | goto out_destroy; |
518 | error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs); | 519 | error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs); |
519 | if (error) | 520 | if (error) |
520 | goto out_shutdown; | 521 | goto out_shutdown; |
521 | /* We are holding a reference to nn->nfsd_serv which | 522 | /* We are holding a reference to nn->nfsd_serv which |
522 | * we don't want to count in the return value, | 523 | * we don't want to count in the return value, |
523 | * so subtract 1 | 524 | * so subtract 1 |
524 | */ | 525 | */ |
525 | error = nn->nfsd_serv->sv_nrthreads - 1; | 526 | error = nn->nfsd_serv->sv_nrthreads - 1; |
526 | out_shutdown: | 527 | out_shutdown: |
527 | if (error < 0 && !nfsd_up_before) | 528 | if (error < 0 && !nfsd_up_before) |
528 | nfsd_shutdown_net(net); | 529 | nfsd_shutdown_net(net); |
529 | out_destroy: | 530 | out_destroy: |
530 | nfsd_destroy(net); /* Release server */ | 531 | nfsd_destroy(net); /* Release server */ |
531 | out: | 532 | out: |
532 | mutex_unlock(&nfsd_mutex); | 533 | mutex_unlock(&nfsd_mutex); |
533 | return error; | 534 | return error; |
534 | } | 535 | } |
535 | 536 | ||
536 | 537 | ||
537 | /* | 538 | /* |
538 | * This is the NFS server kernel thread | 539 | * This is the NFS server kernel thread |
539 | */ | 540 | */ |
540 | static int | 541 | static int |
541 | nfsd(void *vrqstp) | 542 | nfsd(void *vrqstp) |
542 | { | 543 | { |
543 | struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; | 544 | struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; |
544 | struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list); | 545 | struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list); |
545 | struct net *net = perm_sock->xpt_net; | 546 | struct net *net = perm_sock->xpt_net; |
546 | int err; | 547 | int err; |
547 | 548 | ||
548 | /* Lock module and set up kernel thread */ | 549 | /* Lock module and set up kernel thread */ |
549 | mutex_lock(&nfsd_mutex); | 550 | mutex_lock(&nfsd_mutex); |
550 | 551 | ||
551 | /* At this point, the thread shares current->fs | 552 | /* At this point, the thread shares current->fs |
552 | * with the init process. We need to create files with a | 553 | * with the init process. We need to create files with a |
553 | * umask of 0 instead of init's umask. */ | 554 | * umask of 0 instead of init's umask. */ |
554 | if (unshare_fs_struct() < 0) { | 555 | if (unshare_fs_struct() < 0) { |
555 | printk("Unable to start nfsd thread: out of memory\n"); | 556 | printk("Unable to start nfsd thread: out of memory\n"); |
556 | goto out; | 557 | goto out; |
557 | } | 558 | } |
558 | 559 | ||
559 | current->fs->umask = 0; | 560 | current->fs->umask = 0; |
560 | 561 | ||
561 | /* | 562 | /* |
562 | * thread is spawned with all signals set to SIG_IGN, re-enable | 563 | * thread is spawned with all signals set to SIG_IGN, re-enable |
563 | * the ones that will bring down the thread | 564 | * the ones that will bring down the thread |
564 | */ | 565 | */ |
565 | allow_signal(SIGKILL); | 566 | allow_signal(SIGKILL); |
566 | allow_signal(SIGHUP); | 567 | allow_signal(SIGHUP); |
567 | allow_signal(SIGINT); | 568 | allow_signal(SIGINT); |
568 | allow_signal(SIGQUIT); | 569 | allow_signal(SIGQUIT); |
569 | 570 | ||
570 | nfsdstats.th_cnt++; | 571 | nfsdstats.th_cnt++; |
571 | mutex_unlock(&nfsd_mutex); | 572 | mutex_unlock(&nfsd_mutex); |
572 | 573 | ||
573 | /* | 574 | /* |
574 | * We want less throttling in balance_dirty_pages() so that nfs to | 575 | * We want less throttling in balance_dirty_pages() so that nfs to |
575 | * localhost doesn't cause nfsd to lock up due to all the client's | 576 | * localhost doesn't cause nfsd to lock up due to all the client's |
576 | * dirty pages. | 577 | * dirty pages. |
577 | */ | 578 | */ |
578 | current->flags |= PF_LESS_THROTTLE; | 579 | current->flags |= PF_LESS_THROTTLE; |
579 | set_freezable(); | 580 | set_freezable(); |
580 | 581 | ||
581 | /* | 582 | /* |
582 | * The main request loop | 583 | * The main request loop |
583 | */ | 584 | */ |
584 | for (;;) { | 585 | for (;;) { |
585 | /* | 586 | /* |
586 | * Find a socket with data available and call its | 587 | * Find a socket with data available and call its |
587 | * recvfrom routine. | 588 | * recvfrom routine. |
588 | */ | 589 | */ |
589 | while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN) | 590 | while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN) |
590 | ; | 591 | ; |
591 | if (err == -EINTR) | 592 | if (err == -EINTR) |
592 | break; | 593 | break; |
593 | validate_process_creds(); | 594 | validate_process_creds(); |
594 | svc_process(rqstp); | 595 | svc_process(rqstp); |
595 | validate_process_creds(); | 596 | validate_process_creds(); |
596 | } | 597 | } |
597 | 598 | ||
598 | /* Clear signals before calling svc_exit_thread() */ | 599 | /* Clear signals before calling svc_exit_thread() */ |
599 | flush_signals(current); | 600 | flush_signals(current); |
600 | 601 | ||
601 | mutex_lock(&nfsd_mutex); | 602 | mutex_lock(&nfsd_mutex); |
602 | nfsdstats.th_cnt --; | 603 | nfsdstats.th_cnt --; |
603 | 604 | ||
604 | out: | 605 | out: |
605 | rqstp->rq_server = NULL; | 606 | rqstp->rq_server = NULL; |
606 | 607 | ||
607 | /* Release the thread */ | 608 | /* Release the thread */ |
608 | svc_exit_thread(rqstp); | 609 | svc_exit_thread(rqstp); |
609 | 610 | ||
610 | nfsd_destroy(net); | 611 | nfsd_destroy(net); |
611 | 612 | ||
612 | /* Release module */ | 613 | /* Release module */ |
613 | mutex_unlock(&nfsd_mutex); | 614 | mutex_unlock(&nfsd_mutex); |
614 | module_put_and_exit(0); | 615 | module_put_and_exit(0); |
615 | return 0; | 616 | return 0; |
616 | } | 617 | } |
617 | 618 | ||
618 | static __be32 map_new_errors(u32 vers, __be32 nfserr) | 619 | static __be32 map_new_errors(u32 vers, __be32 nfserr) |
619 | { | 620 | { |
620 | if (nfserr == nfserr_jukebox && vers == 2) | 621 | if (nfserr == nfserr_jukebox && vers == 2) |
621 | return nfserr_dropit; | 622 | return nfserr_dropit; |
622 | if (nfserr == nfserr_wrongsec && vers < 4) | 623 | if (nfserr == nfserr_wrongsec && vers < 4) |
623 | return nfserr_acces; | 624 | return nfserr_acces; |
624 | return nfserr; | 625 | return nfserr; |
625 | } | 626 | } |
626 | 627 | ||
627 | int | 628 | int |
628 | nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | 629 | nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) |
629 | { | 630 | { |
630 | struct svc_procedure *proc; | 631 | struct svc_procedure *proc; |
631 | kxdrproc_t xdr; | 632 | kxdrproc_t xdr; |
632 | __be32 nfserr; | 633 | __be32 nfserr; |
633 | __be32 *nfserrp; | 634 | __be32 *nfserrp; |
634 | 635 | ||
635 | dprintk("nfsd_dispatch: vers %d proc %d\n", | 636 | dprintk("nfsd_dispatch: vers %d proc %d\n", |
636 | rqstp->rq_vers, rqstp->rq_proc); | 637 | rqstp->rq_vers, rqstp->rq_proc); |
637 | proc = rqstp->rq_procinfo; | 638 | proc = rqstp->rq_procinfo; |
638 | 639 | ||
639 | /* | 640 | /* |
640 | * Give the xdr decoder a chance to change this if it wants | 641 | * Give the xdr decoder a chance to change this if it wants |
641 | * (necessary in the NFSv4.0 compound case) | 642 | * (necessary in the NFSv4.0 compound case) |
642 | */ | 643 | */ |
643 | rqstp->rq_cachetype = proc->pc_cachetype; | 644 | rqstp->rq_cachetype = proc->pc_cachetype; |
644 | /* Decode arguments */ | 645 | /* Decode arguments */ |
645 | xdr = proc->pc_decode; | 646 | xdr = proc->pc_decode; |
646 | if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base, | 647 | if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base, |
647 | rqstp->rq_argp)) { | 648 | rqstp->rq_argp)) { |
648 | dprintk("nfsd: failed to decode arguments!\n"); | 649 | dprintk("nfsd: failed to decode arguments!\n"); |
649 | *statp = rpc_garbage_args; | 650 | *statp = rpc_garbage_args; |
650 | return 1; | 651 | return 1; |
651 | } | 652 | } |
652 | 653 | ||
653 | /* Check whether we have this call in the cache. */ | 654 | /* Check whether we have this call in the cache. */ |
654 | switch (nfsd_cache_lookup(rqstp)) { | 655 | switch (nfsd_cache_lookup(rqstp)) { |
655 | case RC_DROPIT: | 656 | case RC_DROPIT: |
656 | return 0; | 657 | return 0; |
657 | case RC_REPLY: | 658 | case RC_REPLY: |
658 | return 1; | 659 | return 1; |
659 | case RC_DOIT:; | 660 | case RC_DOIT:; |
660 | /* do it */ | 661 | /* do it */ |
661 | } | 662 | } |
662 | 663 | ||
663 | /* need to grab the location to store the status, as | 664 | /* need to grab the location to store the status, as |
664 | * nfsv4 does some encoding while processing | 665 | * nfsv4 does some encoding while processing |
665 | */ | 666 | */ |
666 | nfserrp = rqstp->rq_res.head[0].iov_base | 667 | nfserrp = rqstp->rq_res.head[0].iov_base |
667 | + rqstp->rq_res.head[0].iov_len; | 668 | + rqstp->rq_res.head[0].iov_len; |
668 | rqstp->rq_res.head[0].iov_len += sizeof(__be32); | 669 | rqstp->rq_res.head[0].iov_len += sizeof(__be32); |
669 | 670 | ||
670 | /* Now call the procedure handler, and encode NFS status. */ | 671 | /* Now call the procedure handler, and encode NFS status. */ |
671 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); | 672 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); |
672 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); | 673 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); |
673 | if (nfserr == nfserr_dropit || rqstp->rq_dropme) { | 674 | if (nfserr == nfserr_dropit || rqstp->rq_dropme) { |
674 | dprintk("nfsd: Dropping request; may be revisited later\n"); | 675 | dprintk("nfsd: Dropping request; may be revisited later\n"); |
675 | nfsd_cache_update(rqstp, RC_NOCACHE, NULL); | 676 | nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
676 | return 0; | 677 | return 0; |
677 | } | 678 | } |
678 | 679 | ||
679 | if (rqstp->rq_proc != 0) | 680 | if (rqstp->rq_proc != 0) |
680 | *nfserrp++ = nfserr; | 681 | *nfserrp++ = nfserr; |
681 | 682 | ||
682 | /* Encode result. | 683 | /* Encode result. |
683 | * For NFSv2, additional info is never returned in case of an error. | 684 | * For NFSv2, additional info is never returned in case of an error. |
684 | */ | 685 | */ |
685 | if (!(nfserr && rqstp->rq_vers == 2)) { | 686 | if (!(nfserr && rqstp->rq_vers == 2)) { |
686 | xdr = proc->pc_encode; | 687 | xdr = proc->pc_encode; |
687 | if (xdr && !xdr(rqstp, nfserrp, | 688 | if (xdr && !xdr(rqstp, nfserrp, |
688 | rqstp->rq_resp)) { | 689 | rqstp->rq_resp)) { |
689 | /* Failed to encode result. Release cache entry */ | 690 | /* Failed to encode result. Release cache entry */ |
690 | dprintk("nfsd: failed to encode result!\n"); | 691 | dprintk("nfsd: failed to encode result!\n"); |
691 | nfsd_cache_update(rqstp, RC_NOCACHE, NULL); | 692 | nfsd_cache_update(rqstp, RC_NOCACHE, NULL); |
692 | *statp = rpc_system_err; | 693 | *statp = rpc_system_err; |
693 | return 1; | 694 | return 1; |
694 | } | 695 | } |
695 | } | 696 | } |
696 | 697 | ||
697 | /* Store reply in cache. */ | 698 | /* Store reply in cache. */ |
698 | nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); | 699 | nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); |
699 | return 1; | 700 | return 1; |
700 | } | 701 | } |
701 | 702 | ||
702 | int nfsd_pool_stats_open(struct inode *inode, struct file *file) | 703 | int nfsd_pool_stats_open(struct inode *inode, struct file *file) |
703 | { | 704 | { |
704 | int ret; | 705 | int ret; |
705 | struct nfsd_net *nn = net_generic(inode->i_sb->s_fs_info, nfsd_net_id); | 706 | struct nfsd_net *nn = net_generic(inode->i_sb->s_fs_info, nfsd_net_id); |
706 | 707 | ||
707 | mutex_lock(&nfsd_mutex); | 708 | mutex_lock(&nfsd_mutex); |
708 | if (nn->nfsd_serv == NULL) { | 709 | if (nn->nfsd_serv == NULL) { |
709 | mutex_unlock(&nfsd_mutex); | 710 | mutex_unlock(&nfsd_mutex); |
710 | return -ENODEV; | 711 | return -ENODEV; |
711 | } | 712 | } |
712 | /* bump up the psudo refcount while traversing */ | 713 | /* bump up the psudo refcount while traversing */ |
713 | svc_get(nn->nfsd_serv); | 714 | svc_get(nn->nfsd_serv); |
714 | ret = svc_pool_stats_open(nn->nfsd_serv, file); | 715 | ret = svc_pool_stats_open(nn->nfsd_serv, file); |
715 | mutex_unlock(&nfsd_mutex); | 716 | mutex_unlock(&nfsd_mutex); |
716 | return ret; | 717 | return ret; |
717 | } | 718 | } |
718 | 719 | ||
719 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) | 720 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) |
720 | { | 721 | { |
721 | int ret = seq_release(inode, file); | 722 | int ret = seq_release(inode, file); |
722 | struct net *net = inode->i_sb->s_fs_info; | 723 | struct net *net = inode->i_sb->s_fs_info; |
723 | 724 | ||
724 | mutex_lock(&nfsd_mutex); | 725 | mutex_lock(&nfsd_mutex); |
725 | /* this function really, really should have been called svc_put() */ | 726 | /* this function really, really should have been called svc_put() */ |
726 | nfsd_destroy(net); | 727 | nfsd_destroy(net); |
727 | mutex_unlock(&nfsd_mutex); | 728 | mutex_unlock(&nfsd_mutex); |
728 | return ret; | 729 | return ret; |